~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to source/blender/python/generic/mathutils_quat.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * $Id: mathutils_quat.c 28786 2010-05-16 10:09:07Z 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_math.h"
32
 
#include "BKE_utildefines.h"
33
 
 
34
 
#define QUAT_SIZE 4
35
 
 
36
 
//-----------------------------METHODS------------------------------
37
 
 
38
 
/* note: BaseMath_ReadCallback must be called beforehand */
39
 
static PyObject *Quaternion_ToTupleExt(QuaternionObject *self, int ndigits)
40
 
{
41
 
        PyObject *ret;
42
 
        int i;
43
 
 
44
 
        ret= PyTuple_New(QUAT_SIZE);
45
 
 
46
 
        if(ndigits >= 0) {
47
 
                for(i= 0; i < QUAT_SIZE; i++) {
48
 
                        PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->quat[i], ndigits)));
49
 
                }
50
 
        }
51
 
        else {
52
 
                for(i= 0; i < QUAT_SIZE; i++) {
53
 
                        PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->quat[i]));
54
 
                }
55
 
        }
56
 
 
57
 
        return ret;
58
 
}
59
 
 
60
 
static char Quaternion_ToEuler_doc[] =
61
 
".. method:: to_euler(order, euler_compat)\n"
62
 
"\n"
63
 
"   Return Euler representation of the quaternion.\n"
64
 
"\n"
65
 
"   :arg order: Optional rotation order argument in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
66
 
"   :type order: string\n"
67
 
"   :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
68
 
"   :type euler_compat: :class:`Euler`\n"
69
 
"   :return: Euler representation of the quaternion.\n"
70
 
"   :rtype: :class:`Euler`\n";
71
 
 
72
 
static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
73
 
{
74
 
        float eul[3];
75
 
        char *order_str= NULL;
76
 
        short order= EULER_ORDER_XYZ;
77
 
        EulerObject *eul_compat = NULL;
78
 
        
79
 
        if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
80
 
                return NULL;
81
 
        
82
 
        if(!BaseMath_ReadCallback(self))
83
 
                return NULL;
84
 
 
85
 
        if(order_str) {
86
 
                order= euler_order_from_string(order_str, "Matrix.to_euler()");
87
 
 
88
 
                if(order == -1)
89
 
                        return NULL;
90
 
        }
91
 
 
92
 
        if(eul_compat) {
93
 
                float mat[3][3];
94
 
                
95
 
                if(!BaseMath_ReadCallback(eul_compat))
96
 
                        return NULL;
97
 
                
98
 
                quat_to_mat3(mat, self->quat);
99
 
 
100
 
                if(order == EULER_ORDER_XYZ)    mat3_to_compatible_eul(eul, eul_compat->eul, mat);
101
 
                else                                                    mat3_to_compatible_eulO(eul, eul_compat->eul, order, mat);
102
 
        }
103
 
        else {
104
 
                if(order == EULER_ORDER_XYZ)    quat_to_eul(eul, self->quat);
105
 
                else                                                    quat_to_eulO(eul, order, self->quat);
106
 
        }
107
 
        
108
 
        return newEulerObject(eul, order, Py_NEW, NULL);
109
 
}
110
 
//----------------------------Quaternion.toMatrix()------------------
111
 
static char Quaternion_ToMatrix_doc[] =
112
 
".. method:: to_matrix(other)\n"
113
 
"\n"
114
 
"   Return a matrix representation of the quaternion.\n"
115
 
"\n"
116
 
"   :return: A 3x3 rotation matrix representation of the quaternion.\n"
117
 
"   :rtype: :class:`Matrix`\n";
118
 
 
119
 
static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
120
 
{
121
 
        float mat[9]; /* all values are set */
122
 
 
123
 
        if(!BaseMath_ReadCallback(self))
124
 
                return NULL;
125
 
 
126
 
        quat_to_mat3( (float (*)[3]) mat,self->quat);
127
 
        return newMatrixObject(mat, 3, 3, Py_NEW, NULL);
128
 
}
129
 
 
130
 
//----------------------------Quaternion.cross(other)------------------
131
 
static char Quaternion_Cross_doc[] =
132
 
".. method:: cross(other)\n"
133
 
"\n"
134
 
"   Return the cross product of this quaternion and another.\n"
135
 
"\n"
136
 
"   :arg other: The other quaternion to perform the cross product with.\n"
137
 
"   :type other: :class:`Quaternion`\n"
138
 
"   :return: The cross product.\n"
139
 
"   :rtype: :class:`Quaternion`\n";
140
 
 
141
 
static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value)
142
 
{
143
 
        float quat[QUAT_SIZE];
144
 
        
145
 
        if (!QuaternionObject_Check(value)) {
146
 
                PyErr_SetString( PyExc_TypeError, "quat.cross(value): expected a quaternion argument" );
147
 
                return NULL;
148
 
        }
149
 
        
150
 
        if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
151
 
                return NULL;
152
 
 
153
 
        mul_qt_qtqt(quat, self->quat, value->quat);
154
 
        return newQuaternionObject(quat, Py_NEW, NULL);
155
 
}
156
 
 
157
 
//----------------------------Quaternion.dot(other)------------------
158
 
static char Quaternion_Dot_doc[] =
159
 
".. method:: dot(other)\n"
160
 
"\n"
161
 
"   Return the dot product of this quaternion and another.\n"
162
 
"\n"
163
 
"   :arg other: The other quaternion to perform the dot product with.\n"
164
 
"   :type other: :class:`Quaternion`\n"
165
 
"   :return: The dot product.\n"
166
 
"   :rtype: :class:`Quaternion`\n";
167
 
 
168
 
static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value)
169
 
{
170
 
        if (!QuaternionObject_Check(value)) {
171
 
                PyErr_SetString( PyExc_TypeError, "quat.dot(value): expected a quaternion argument" );
172
 
                return NULL;
173
 
        }
174
 
 
175
 
        if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
176
 
                return NULL;
177
 
 
178
 
        return PyFloat_FromDouble(dot_qtqt(self->quat, value->quat));
179
 
}
180
 
 
181
 
static char Quaternion_Difference_doc[] =
182
 
".. function:: difference(other)\n"
183
 
"\n"
184
 
"   Returns a quaternion representing the rotational difference.\n"
185
 
"\n"
186
 
"   :arg other: second quaternion.\n"
187
 
"   :type other: :class:`Quaternion`\n"
188
 
"   :return: the rotational difference between the two quat rotations.\n"
189
 
"   :rtype: :class:`Quaternion`\n";
190
 
 
191
 
static PyObject *Quaternion_Difference(QuaternionObject * self, QuaternionObject * value)
192
 
{
193
 
        float quat[QUAT_SIZE], tempQuat[QUAT_SIZE];
194
 
        double dot = 0.0f;
195
 
        int x;
196
 
 
197
 
        if (!QuaternionObject_Check(value)) {
198
 
                PyErr_SetString( PyExc_TypeError, "quat.difference(value): expected a quaternion argument" );
199
 
                return NULL;
200
 
        }
201
 
 
202
 
        if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
203
 
                return NULL;
204
 
 
205
 
        copy_qt_qt(tempQuat, self->quat);
206
 
        conjugate_qt(tempQuat);
207
 
        dot = sqrt(dot_qtqt(tempQuat, tempQuat));
208
 
 
209
 
        for(x = 0; x < QUAT_SIZE; x++) {
210
 
                tempQuat[x] /= (float)(dot * dot);
211
 
        }
212
 
        mul_qt_qtqt(quat, tempQuat, value->quat);
213
 
        return newQuaternionObject(quat, Py_NEW, NULL);
214
 
}
215
 
 
216
 
static char Quaternion_Slerp_doc[] =
217
 
".. function:: slerp(other, factor)\n"
218
 
"\n"
219
 
"   Returns the interpolation of two quaternions.\n"
220
 
"\n"
221
 
"   :arg other: value to interpolate with.\n"
222
 
"   :type other: :class:`Quaternion`\n"
223
 
"   :arg factor: The interpolation value in [0.0, 1.0].\n"
224
 
"   :type factor: float\n"
225
 
"   :return: The interpolated rotation.\n"
226
 
"   :rtype: :class:`Quaternion`\n";
227
 
 
228
 
static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args)
229
 
{
230
 
        QuaternionObject *value;
231
 
        float quat[QUAT_SIZE], fac;
232
 
 
233
 
        if(!PyArg_ParseTuple(args, "O!f:slerp", &quaternion_Type, &value, &fac)) {
234
 
                PyErr_SetString(PyExc_TypeError, "quat.slerp(): expected Quaternion types and float");
235
 
                return NULL;
236
 
        }
237
 
 
238
 
        if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
239
 
                return NULL;
240
 
 
241
 
        if(fac > 1.0f || fac < 0.0f) {
242
 
                PyErr_SetString(PyExc_AttributeError, "quat.slerp(): interpolation factor must be between 0.0 and 1.0");
243
 
                return NULL;
244
 
        }
245
 
 
246
 
        interp_qt_qtqt(quat, self->quat, value->quat, fac);
247
 
 
248
 
        return newQuaternionObject(quat, Py_NEW, NULL);
249
 
}
250
 
 
251
 
//----------------------------Quaternion.normalize()----------------
252
 
//normalize the axis of rotation of [theta,vector]
253
 
static char Quaternion_Normalize_doc[] =
254
 
".. function:: normalize()\n"
255
 
"\n"
256
 
"   Normalize the quaternion.\n"
257
 
"\n"
258
 
"   :return: an instance of itself.\n"
259
 
"   :rtype: :class:`Quaternion`\n";
260
 
 
261
 
static PyObject *Quaternion_Normalize(QuaternionObject * self)
262
 
{
263
 
        if(!BaseMath_ReadCallback(self))
264
 
                return NULL;
265
 
 
266
 
        normalize_qt(self->quat);
267
 
 
268
 
        BaseMath_WriteCallback(self);
269
 
        Py_INCREF(self);
270
 
        return (PyObject*)self;
271
 
}
272
 
//----------------------------Quaternion.inverse()------------------
273
 
static char Quaternion_Inverse_doc[] =
274
 
".. function:: inverse()\n"
275
 
"\n"
276
 
"   Set the quaternion to its inverse.\n"
277
 
"\n"
278
 
"   :return: an instance of itself.\n"
279
 
"   :rtype: :class:`Quaternion`\n";
280
 
 
281
 
static PyObject *Quaternion_Inverse(QuaternionObject * self)
282
 
{
283
 
        if(!BaseMath_ReadCallback(self))
284
 
                return NULL;
285
 
 
286
 
        invert_qt(self->quat);
287
 
 
288
 
        BaseMath_WriteCallback(self);
289
 
        Py_INCREF(self);
290
 
        return (PyObject*)self;
291
 
}
292
 
//----------------------------Quaternion.identity()-----------------
293
 
static char Quaternion_Identity_doc[] =
294
 
".. function:: identity()\n"
295
 
"\n"
296
 
"   Set the quaternion to an identity quaternion.\n"
297
 
"\n"
298
 
"   :return: an instance of itself.\n"
299
 
"   :rtype: :class:`Quaternion`\n";
300
 
 
301
 
static PyObject *Quaternion_Identity(QuaternionObject * self)
302
 
{
303
 
        if(!BaseMath_ReadCallback(self))
304
 
                return NULL;
305
 
 
306
 
        unit_qt(self->quat);
307
 
 
308
 
        BaseMath_WriteCallback(self);
309
 
        Py_INCREF(self);
310
 
        return (PyObject*)self;
311
 
}
312
 
//----------------------------Quaternion.negate()-------------------
313
 
static char Quaternion_Negate_doc[] =
314
 
".. function:: negate()\n"
315
 
"\n"
316
 
"   Set the quaternion to its negative.\n"
317
 
"\n"
318
 
"   :return: an instance of itself.\n"
319
 
"   :rtype: :class:`Quaternion`\n";
320
 
 
321
 
static PyObject *Quaternion_Negate(QuaternionObject * self)
322
 
{
323
 
        if(!BaseMath_ReadCallback(self))
324
 
                return NULL;
325
 
 
326
 
        mul_qt_fl(self->quat, -1.0f);
327
 
 
328
 
        BaseMath_WriteCallback(self);
329
 
        Py_INCREF(self);
330
 
        return (PyObject*)self;
331
 
}
332
 
//----------------------------Quaternion.conjugate()----------------
333
 
static char Quaternion_Conjugate_doc[] =
334
 
".. function:: conjugate()\n"
335
 
"\n"
336
 
"   Set the quaternion to its conjugate (negate x, y, z).\n"
337
 
"\n"
338
 
"   :return: an instance of itself.\n"
339
 
"   :rtype: :class:`Quaternion`\n";
340
 
 
341
 
static PyObject *Quaternion_Conjugate(QuaternionObject * self)
342
 
{
343
 
        if(!BaseMath_ReadCallback(self))
344
 
                return NULL;
345
 
 
346
 
        conjugate_qt(self->quat);
347
 
 
348
 
        BaseMath_WriteCallback(self);
349
 
        Py_INCREF(self);
350
 
        return (PyObject*)self;
351
 
}
352
 
//----------------------------Quaternion.copy()----------------
353
 
static char Quaternion_copy_doc[] =
354
 
".. function:: copy()\n"
355
 
"\n"
356
 
"   Returns a copy of this quaternion.\n"
357
 
"\n"
358
 
"   :return: A copy of the quaternion.\n"
359
 
"   :rtype: :class:`Quaternion`\n"
360
 
"\n"
361
 
"   .. note:: use this to get a copy of a wrapped quaternion with no reference to the original data.\n";
362
 
 
363
 
static PyObject *Quaternion_copy(QuaternionObject * self)
364
 
{
365
 
        if(!BaseMath_ReadCallback(self))
366
 
                return NULL;
367
 
 
368
 
        return newQuaternionObject(self->quat, Py_NEW, Py_TYPE(self));
369
 
}
370
 
 
371
 
//----------------------------print object (internal)--------------
372
 
//print the object to screen
373
 
static PyObject *Quaternion_repr(QuaternionObject * self)
374
 
{
375
 
        PyObject *ret, *tuple;
376
 
        
377
 
        if(!BaseMath_ReadCallback(self))
378
 
                return NULL;
379
 
 
380
 
        tuple= Quaternion_ToTupleExt(self, -1);
381
 
 
382
 
        ret= PyUnicode_FromFormat("Quaternion(%R)", tuple);
383
 
 
384
 
        Py_DECREF(tuple);
385
 
        return ret;
386
 
}
387
 
 
388
 
//------------------------tp_richcmpr
389
 
//returns -1 execption, 0 false, 1 true
390
 
static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
391
 
{
392
 
        QuaternionObject *quatA = NULL, *quatB = NULL;
393
 
        int result = 0;
394
 
 
395
 
        if(QuaternionObject_Check(objectA)) {
396
 
                quatA = (QuaternionObject*)objectA;
397
 
                if(!BaseMath_ReadCallback(quatA))
398
 
                        return NULL;
399
 
        }
400
 
        if(QuaternionObject_Check(objectB)) {
401
 
                quatB = (QuaternionObject*)objectB;
402
 
                if(!BaseMath_ReadCallback(quatB))
403
 
                        return NULL;
404
 
        }
405
 
 
406
 
        if (!quatA || !quatB){
407
 
                if (comparison_type == Py_NE){
408
 
                        Py_RETURN_TRUE;
409
 
                }else{
410
 
                        Py_RETURN_FALSE;
411
 
                }
412
 
        }
413
 
 
414
 
        switch (comparison_type){
415
 
                case Py_EQ:
416
 
                        result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1);
417
 
                        break;
418
 
                case Py_NE:
419
 
                        result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1);
420
 
                        if (result == 0){
421
 
                                result = 1;
422
 
                        }else{
423
 
                                result = 0;
424
 
                        }
425
 
                        break;
426
 
                default:
427
 
                        printf("The result of the comparison could not be evaluated");
428
 
                        break;
429
 
        }
430
 
        if (result == 1){
431
 
                Py_RETURN_TRUE;
432
 
        }else{
433
 
                Py_RETURN_FALSE;
434
 
        }
435
 
}
436
 
 
437
 
//---------------------SEQUENCE PROTOCOLS------------------------
438
 
//----------------------------len(object)------------------------
439
 
//sequence length
440
 
static int Quaternion_len(QuaternionObject * self)
441
 
{
442
 
        return QUAT_SIZE;
443
 
}
444
 
//----------------------------object[]---------------------------
445
 
//sequence accessor (get)
446
 
static PyObject *Quaternion_item(QuaternionObject * self, int i)
447
 
{
448
 
        if(i<0) i= QUAT_SIZE-i;
449
 
 
450
 
        if(i < 0 || i >= QUAT_SIZE) {
451
 
                PyErr_SetString(PyExc_IndexError, "quaternion[attribute]: array index out of range\n");
452
 
                return NULL;
453
 
        }
454
 
 
455
 
        if(!BaseMath_ReadIndexCallback(self, i))
456
 
                return NULL;
457
 
 
458
 
        return PyFloat_FromDouble(self->quat[i]);
459
 
 
460
 
}
461
 
//----------------------------object[]-------------------------
462
 
//sequence accessor (set)
463
 
static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
464
 
{
465
 
        float scalar= (float)PyFloat_AsDouble(ob);
466
 
        if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
467
 
                PyErr_SetString(PyExc_TypeError, "quaternion[index] = x: index argument not a number\n");
468
 
                return -1;
469
 
        }
470
 
 
471
 
        if(i<0) i= QUAT_SIZE-i;
472
 
 
473
 
        if(i < 0 || i >= QUAT_SIZE){
474
 
                PyErr_SetString(PyExc_IndexError, "quaternion[attribute] = x: array assignment index out of range\n");
475
 
                return -1;
476
 
        }
477
 
        self->quat[i] = scalar;
478
 
 
479
 
        if(!BaseMath_WriteIndexCallback(self, i))
480
 
                return -1;
481
 
 
482
 
        return 0;
483
 
}
484
 
//----------------------------object[z:y]------------------------
485
 
//sequence slice (get)
486
 
static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
487
 
{
488
 
        PyObject *list = NULL;
489
 
        int count;
490
 
 
491
 
        if(!BaseMath_ReadCallback(self))
492
 
                return NULL;
493
 
 
494
 
        CLAMP(begin, 0, QUAT_SIZE);
495
 
        if (end<0) end= (QUAT_SIZE + 1) + end;
496
 
        CLAMP(end, 0, QUAT_SIZE);
497
 
        begin = MIN2(begin,end);
498
 
 
499
 
        list = PyList_New(end - begin);
500
 
        for(count = begin; count < end; count++) {
501
 
                PyList_SetItem(list, count - begin,
502
 
                                PyFloat_FromDouble(self->quat[count]));
503
 
        }
504
 
 
505
 
        return list;
506
 
}
507
 
//----------------------------object[z:y]------------------------
508
 
//sequence slice (set)
509
 
static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyObject * seq)
510
 
{
511
 
        int i, size;
512
 
        float quat[QUAT_SIZE];
513
 
 
514
 
        if(!BaseMath_ReadCallback(self))
515
 
                return -1;
516
 
 
517
 
        CLAMP(begin, 0, QUAT_SIZE);
518
 
        if (end<0) end= (QUAT_SIZE + 1) + end;
519
 
        CLAMP(end, 0, QUAT_SIZE);
520
 
        begin = MIN2(begin,end);
521
 
 
522
 
        if((size=mathutils_array_parse(quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1)
523
 
                return -1;
524
 
        
525
 
        if(size != (end - begin)){
526
 
                PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: size mismatch in slice assignment");
527
 
                return -1;
528
 
        }
529
 
 
530
 
        /* parsed well - now set in vector */
531
 
        for(i= 0; i < size; i++)
532
 
                self->quat[begin + i] = quat[i];
533
 
 
534
 
        BaseMath_WriteCallback(self);
535
 
        return 0;
536
 
}
537
 
 
538
 
 
539
 
static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
540
 
{
541
 
        if (PyIndex_Check(item)) {
542
 
                Py_ssize_t i;
543
 
                i = PyNumber_AsSsize_t(item, PyExc_IndexError);
544
 
                if (i == -1 && PyErr_Occurred())
545
 
                        return NULL;
546
 
                if (i < 0)
547
 
                        i += QUAT_SIZE;
548
 
                return Quaternion_item(self, i);
549
 
        } else if (PySlice_Check(item)) {
550
 
                Py_ssize_t start, stop, step, slicelength;
551
 
 
552
 
                if (PySlice_GetIndicesEx((PySliceObject*)item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0)
553
 
                        return NULL;
554
 
 
555
 
                if (slicelength <= 0) {
556
 
                        return PyList_New(0);
557
 
                }
558
 
                else if (step == 1) {
559
 
                        return Quaternion_slice(self, start, stop);
560
 
                }
561
 
                else {
562
 
                        PyErr_SetString(PyExc_TypeError, "slice steps not supported with quaternions");
563
 
                        return NULL;
564
 
                }
565
 
        }
566
 
        else {
567
 
                PyErr_Format(PyExc_TypeError,
568
 
                                 "quaternion indices must be integers, not %.200s",
569
 
                                 item->ob_type->tp_name);
570
 
                return NULL;
571
 
        }
572
 
}
573
 
 
574
 
 
575
 
static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
576
 
{
577
 
        if (PyIndex_Check(item)) {
578
 
                Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
579
 
                if (i == -1 && PyErr_Occurred())
580
 
                        return -1;
581
 
                if (i < 0)
582
 
                        i += QUAT_SIZE;
583
 
                return Quaternion_ass_item(self, i, value);
584
 
        }
585
 
        else if (PySlice_Check(item)) {
586
 
                Py_ssize_t start, stop, step, slicelength;
587
 
 
588
 
                if (PySlice_GetIndicesEx((PySliceObject*)item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0)
589
 
                        return -1;
590
 
 
591
 
                if (step == 1)
592
 
                        return Quaternion_ass_slice(self, start, stop, value);
593
 
                else {
594
 
                        PyErr_SetString(PyExc_TypeError, "slice steps not supported with quaternion");
595
 
                        return -1;
596
 
                }
597
 
        }
598
 
        else {
599
 
                PyErr_Format(PyExc_TypeError,
600
 
                                 "quaternion indices must be integers, not %.200s",
601
 
                                 item->ob_type->tp_name);
602
 
                return -1;
603
 
        }
604
 
}
605
 
 
606
 
//------------------------NUMERIC PROTOCOLS----------------------
607
 
//------------------------obj + obj------------------------------
608
 
//addition
609
 
static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
610
 
{
611
 
        float quat[QUAT_SIZE];
612
 
        QuaternionObject *quat1 = NULL, *quat2 = NULL;
613
 
 
614
 
        if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
615
 
                PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n");
616
 
                return NULL;
617
 
        }
618
 
        quat1 = (QuaternionObject*)q1;
619
 
        quat2 = (QuaternionObject*)q2;
620
 
        
621
 
        if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
622
 
                return NULL;
623
 
 
624
 
        add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
625
 
        return newQuaternionObject(quat, Py_NEW, NULL);
626
 
}
627
 
//------------------------obj - obj------------------------------
628
 
//subtraction
629
 
static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
630
 
{
631
 
        int x;
632
 
        float quat[QUAT_SIZE];
633
 
        QuaternionObject *quat1 = NULL, *quat2 = NULL;
634
 
 
635
 
        if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
636
 
                PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n");
637
 
                return NULL;
638
 
        }
639
 
        
640
 
        quat1 = (QuaternionObject*)q1;
641
 
        quat2 = (QuaternionObject*)q2;
642
 
        
643
 
        if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
644
 
                return NULL;
645
 
 
646
 
        for(x = 0; x < QUAT_SIZE; x++) {
647
 
                quat[x] = quat1->quat[x] - quat2->quat[x];
648
 
        }
649
 
 
650
 
        return newQuaternionObject(quat, Py_NEW, NULL);
651
 
}
652
 
//------------------------obj * obj------------------------------
653
 
//mulplication
654
 
static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
655
 
{
656
 
        float quat[QUAT_SIZE], scalar;
657
 
        QuaternionObject *quat1 = NULL, *quat2 = NULL;
658
 
        VectorObject *vec = NULL;
659
 
 
660
 
        if(QuaternionObject_Check(q1)) {
661
 
                quat1 = (QuaternionObject*)q1;
662
 
                if(!BaseMath_ReadCallback(quat1))
663
 
                        return NULL;
664
 
        }
665
 
        if(QuaternionObject_Check(q2)) {
666
 
                quat2 = (QuaternionObject*)q2;
667
 
                if(!BaseMath_ReadCallback(quat2))
668
 
                        return NULL;
669
 
        }
670
 
 
671
 
        if(quat1 && quat2) { /* QUAT*QUAT (dot product) */
672
 
                return PyFloat_FromDouble(dot_qtqt(quat1->quat, quat2->quat));
673
 
        }
674
 
        
675
 
        /* the only case this can happen (for a supported type is "FLOAT*QUAT" ) */
676
 
        if(!QuaternionObject_Check(q1)) {
677
 
                scalar= PyFloat_AsDouble(q1);
678
 
                if ((scalar == -1.0 && PyErr_Occurred())==0) { /* FLOAT*QUAT */
679
 
                        QUATCOPY(quat, quat2->quat);
680
 
                        mul_qt_fl(quat, scalar);
681
 
                        return newQuaternionObject(quat, Py_NEW, NULL);
682
 
                }
683
 
                PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: val * quat, val is not an acceptable type");
684
 
                return NULL;
685
 
        }
686
 
        else { /* QUAT*SOMETHING */
687
 
                if(VectorObject_Check(q2)){  /* QUAT*VEC */
688
 
                        vec = (VectorObject*)q2;
689
 
                        if(vec->size != 3){
690
 
                                PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n");
691
 
                                return NULL;
692
 
                        }
693
 
                        return quat_rotation((PyObject*)quat1, (PyObject*)vec); /* vector updating done inside the func */
694
 
                }
695
 
                
696
 
                scalar= PyFloat_AsDouble(q2);
697
 
                if ((scalar == -1.0 && PyErr_Occurred())==0) { /* QUAT*FLOAT */
698
 
                        QUATCOPY(quat, quat1->quat);
699
 
                        mul_qt_fl(quat, scalar);
700
 
                        return newQuaternionObject(quat, Py_NEW, NULL);
701
 
                }
702
 
        }
703
 
        
704
 
        PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: arguments not acceptable for this operation\n");
705
 
        return NULL;
706
 
}
707
 
 
708
 
//-----------------PROTOCOL DECLARATIONS--------------------------
709
 
static PySequenceMethods Quaternion_SeqMethods = {
710
 
        (lenfunc) Quaternion_len,                               /* sq_length */
711
 
        (binaryfunc) NULL,                                              /* sq_concat */
712
 
        (ssizeargfunc) NULL,                                    /* sq_repeat */
713
 
        (ssizeargfunc) Quaternion_item,                 /* sq_item */
714
 
        (ssizessizeargfunc) NULL,                               /* sq_slice, deprecated */
715
 
        (ssizeobjargproc) Quaternion_ass_item,  /* sq_ass_item */
716
 
        (ssizessizeobjargproc) NULL,                    /* sq_ass_slice, deprecated */
717
 
        (objobjproc) NULL,                                              /* sq_contains */
718
 
        (binaryfunc) NULL,                                              /* sq_inplace_concat */
719
 
        (ssizeargfunc) NULL,                                    /* sq_inplace_repeat */
720
 
};
721
 
 
722
 
static PyMappingMethods Quaternion_AsMapping = {
723
 
        (lenfunc)Quaternion_len,
724
 
        (binaryfunc)Quaternion_subscript,
725
 
        (objobjargproc)Quaternion_ass_subscript
726
 
};
727
 
 
728
 
static PyNumberMethods Quaternion_NumMethods = {
729
 
        (binaryfunc)    Quaternion_add, /*nb_add*/
730
 
        (binaryfunc)    Quaternion_sub, /*nb_subtract*/
731
 
        (binaryfunc)    Quaternion_mul, /*nb_multiply*/
732
 
        0,                                                      /*nb_remainder*/
733
 
        0,                                                      /*nb_divmod*/
734
 
        0,                                                      /*nb_power*/
735
 
        (unaryfunc)     0,      /*nb_negative*/
736
 
        (unaryfunc)     0,      /*tp_positive*/
737
 
        (unaryfunc)     0,      /*tp_absolute*/
738
 
        (inquiry)       0,      /*tp_bool*/
739
 
        (unaryfunc)     0,      /*nb_invert*/
740
 
        0,                              /*nb_lshift*/
741
 
        (binaryfunc)0,  /*nb_rshift*/
742
 
        0,                              /*nb_and*/
743
 
        0,                              /*nb_xor*/
744
 
        0,                              /*nb_or*/
745
 
        0,                              /*nb_int*/
746
 
        0,                              /*nb_reserved*/
747
 
        0,                              /*nb_float*/
748
 
        0,                              /* nb_inplace_add */
749
 
        0,                              /* nb_inplace_subtract */
750
 
        0,                              /* nb_inplace_multiply */
751
 
        0,                              /* nb_inplace_remainder */
752
 
        0,                              /* nb_inplace_power */
753
 
        0,                              /* nb_inplace_lshift */
754
 
        0,                              /* nb_inplace_rshift */
755
 
        0,                              /* nb_inplace_and */
756
 
        0,                              /* nb_inplace_xor */
757
 
        0,                              /* nb_inplace_or */
758
 
        0,                              /* nb_floor_divide */
759
 
        0,                              /* nb_true_divide */
760
 
        0,                              /* nb_inplace_floor_divide */
761
 
        0,                              /* nb_inplace_true_divide */
762
 
        0,                              /* nb_index */
763
 
};
764
 
 
765
 
static PyObject *Quaternion_getAxis( QuaternionObject * self, void *type )
766
 
{
767
 
        return Quaternion_item(self, GET_INT_FROM_POINTER(type));
768
 
}
769
 
 
770
 
static int Quaternion_setAxis( QuaternionObject * self, PyObject * value, void * type )
771
 
{
772
 
        return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value);
773
 
}
774
 
 
775
 
static PyObject *Quaternion_getMagnitude( QuaternionObject * self, void *type )
776
 
{
777
 
        return PyFloat_FromDouble(sqrt(dot_qtqt(self->quat, self->quat)));
778
 
}
779
 
 
780
 
static PyObject *Quaternion_getAngle( QuaternionObject * self, void *type )
781
 
{
782
 
        return PyFloat_FromDouble(2.0 * (saacos(self->quat[0])));
783
 
}
784
 
 
785
 
static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type )
786
 
{
787
 
        float vec[3];
788
 
 
789
 
        normalize_v3_v3(vec, self->quat+1);
790
 
 
791
 
        /* If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations */
792
 
        if( EXPP_FloatsAreEqual(vec[0], 0.0f, 10) &&
793
 
                EXPP_FloatsAreEqual(vec[1], 0.0f, 10) &&
794
 
                EXPP_FloatsAreEqual(vec[2], 0.0f, 10) ){
795
 
                vec[0] = 1.0f;
796
 
        }
797
 
        return (PyObject *) newVectorObject(vec, 3, Py_NEW, NULL);
798
 
}
799
 
 
800
 
//----------------------------------mathutils.Quaternion() --------------
801
 
static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
802
 
{
803
 
        PyObject *seq= NULL;
804
 
        float angle = 0.0f;
805
 
        float quat[QUAT_SIZE]= {0.0f, 0.0f, 0.0f, 0.0f};
806
 
 
807
 
        if(!PyArg_ParseTuple(args, "|Of:mathutils.Quaternion", &seq, &angle))
808
 
                return NULL;
809
 
 
810
 
        switch(PyTuple_GET_SIZE(args)) {
811
 
        case 0:
812
 
                break;
813
 
        case 1:
814
 
                if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq, "mathutils.Quaternion()") == -1)
815
 
                        return NULL;
816
 
                break;
817
 
        case 2:
818
 
                if (mathutils_array_parse(quat, 3, 3, seq, "mathutils.Quaternion()") == -1)
819
 
                        return NULL;
820
 
 
821
 
                axis_angle_to_quat(quat, quat, angle);
822
 
                break;
823
 
        /* PyArg_ParseTuple assures no more then 2 */
824
 
        }
825
 
        return newQuaternionObject(quat, Py_NEW, NULL);
826
 
}
827
 
 
828
 
 
829
 
//-----------------------METHOD DEFINITIONS ----------------------
830
 
static struct PyMethodDef Quaternion_methods[] = {
831
 
        {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc},
832
 
        {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc},
833
 
        {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc},
834
 
        {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc},
835
 
        {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc},
836
 
        {"to_euler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, Quaternion_ToEuler_doc},
837
 
        {"to_matrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc},
838
 
        {"cross", (PyCFunction) Quaternion_Cross, METH_O, Quaternion_Cross_doc},
839
 
        {"dot", (PyCFunction) Quaternion_Dot, METH_O, Quaternion_Dot_doc},
840
 
        {"difference", (PyCFunction) Quaternion_Difference, METH_O, Quaternion_Difference_doc},
841
 
        {"slerp", (PyCFunction) Quaternion_Slerp, METH_VARARGS, Quaternion_Slerp_doc},
842
 
        {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
843
 
        {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
844
 
        {NULL, NULL, 0, NULL}
845
 
};
846
 
 
847
 
/*****************************************************************************/
848
 
/* Python attributes get/set structure:                                      */
849
 
/*****************************************************************************/
850
 
static PyGetSetDef Quaternion_getseters[] = {
851
 
        {"w", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion W value. **type** float", (void *)0},
852
 
        {"x", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion X axis. **type** float", (void *)1},
853
 
        {"y", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion Y axis. **type** float", (void *)2},
854
 
        {"z", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion Z axis. **type** float", (void *)3},
855
 
        {"magnitude", (getter)Quaternion_getMagnitude, (setter)NULL, "Size of the quaternion (readonly). **type** float", NULL},
856
 
        {"angle", (getter)Quaternion_getAngle, (setter)NULL, "angle of the quaternion (readonly). **type** float", NULL},
857
 
        {"axis",(getter)Quaternion_getAxisVec, (setter)NULL, "quaternion axis as a vector (readonly). **type** :class:`Vector`", NULL},
858
 
        {"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
859
 
        {"_owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
860
 
        {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
861
 
};
862
 
 
863
 
//------------------PY_OBECT DEFINITION--------------------------
864
 
static char quaternion_doc[] =
865
 
"This object gives access to Quaternions in Blender.";
866
 
 
867
 
PyTypeObject quaternion_Type = {
868
 
        PyVarObject_HEAD_INIT(NULL, 0)
869
 
        "quaternion",                                           //tp_name
870
 
        sizeof(QuaternionObject),                       //tp_basicsize
871
 
        0,                                                              //tp_itemsize
872
 
        (destructor)BaseMathObject_dealloc,             //tp_dealloc
873
 
        0,                                                              //tp_print
874
 
        0,                                                              //tp_getattr
875
 
        0,                                                              //tp_setattr
876
 
        0,                                                              //tp_compare
877
 
        (reprfunc) Quaternion_repr,             //tp_repr
878
 
        &Quaternion_NumMethods,                 //tp_as_number
879
 
        &Quaternion_SeqMethods,                 //tp_as_sequence
880
 
        &Quaternion_AsMapping,                  //tp_as_mapping
881
 
        0,                                                              //tp_hash
882
 
        0,                                                              //tp_call
883
 
        0,                                                              //tp_str
884
 
        0,                                                              //tp_getattro
885
 
        0,                                                              //tp_setattro
886
 
        0,                                                              //tp_as_buffer
887
 
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
888
 
        quaternion_doc, //tp_doc
889
 
        0,                                                              //tp_traverse
890
 
        0,                                                              //tp_clear
891
 
        (richcmpfunc)Quaternion_richcmpr,       //tp_richcompare
892
 
        0,                                                              //tp_weaklistoffset
893
 
        0,                                                              //tp_iter
894
 
        0,                                                              //tp_iternext
895
 
        Quaternion_methods,                             //tp_methods
896
 
        0,                                                              //tp_members
897
 
        Quaternion_getseters,                   //tp_getset
898
 
        0,                                                              //tp_base
899
 
        0,                                                              //tp_dict
900
 
        0,                                                              //tp_descr_get
901
 
        0,                                                              //tp_descr_set
902
 
        0,                                                              //tp_dictoffset
903
 
        0,                                                              //tp_init
904
 
        0,                                                              //tp_alloc
905
 
        Quaternion_new,                                 //tp_new
906
 
        0,                                                              //tp_free
907
 
        0,                                                              //tp_is_gc
908
 
        0,                                                              //tp_bases
909
 
        0,                                                              //tp_mro
910
 
        0,                                                              //tp_cache
911
 
        0,                                                              //tp_subclasses
912
 
        0,                                                              //tp_weaklist
913
 
        0                                                               //tp_del
914
 
};
915
 
//------------------------newQuaternionObject (internal)-------------
916
 
//creates a new quaternion object
917
 
/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
918
 
 (i.e. it was allocated elsewhere by MEM_mallocN())
919
 
  pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
920
 
 (i.e. it must be created here with PyMEM_malloc())*/
921
 
PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type)
922
 
{
923
 
        QuaternionObject *self;
924
 
        
925
 
        if(base_type)   self = (QuaternionObject *)base_type->tp_alloc(base_type, 0);
926
 
        else                    self = PyObject_NEW(QuaternionObject, &quaternion_Type);
927
 
 
928
 
        /* init callbacks as NULL */
929
 
        self->cb_user= NULL;
930
 
        self->cb_type= self->cb_subtype= 0;
931
 
 
932
 
        if(type == Py_WRAP){
933
 
                self->quat = quat;
934
 
                self->wrapped = Py_WRAP;
935
 
        }else if (type == Py_NEW){
936
 
                self->quat = PyMem_Malloc(QUAT_SIZE * sizeof(float));
937
 
                if(!quat) { //new empty
938
 
                        unit_qt(self->quat);
939
 
                }else{
940
 
                        QUATCOPY(self->quat, quat);
941
 
                }
942
 
                self->wrapped = Py_NEW;
943
 
        }else{ //bad type
944
 
                return NULL;
945
 
        }
946
 
        return (PyObject *) self;
947
 
}
948
 
 
949
 
PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
950
 
{
951
 
        QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW, NULL);
952
 
        if(self) {
953
 
                Py_INCREF(cb_user);
954
 
                self->cb_user=                  cb_user;
955
 
                self->cb_type=                  (unsigned char)cb_type;
956
 
                self->cb_subtype=               (unsigned char)cb_subtype;
957
 
        }
958
 
 
959
 
        return (PyObject *)self;
960
 
}
961