Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Gilbert <ascotan@gmail.com>2005-07-14 07:34:56 +0400
committerJoseph Gilbert <ascotan@gmail.com>2005-07-14 07:34:56 +0400
commitb89035906daa352ac8eae4c157c3dd6f61b7ad62 (patch)
treed3e3312fb8e282c327b6cb4f7b1f780ce299afa2 /source/blender/python/api2_2x/quat.c
parent1bfd0eae148af20ed97992d44a66f5a6ec34571c (diff)
Mathutils update
- also included is some fixes for preprocessor inclues and some clean up of the previous commit -rewrite and bugfixes ---------------------------------- Here's my changelog: -fixed Rand() so that it doesn't seed everytime and should generate better random numbers - changed a few error return types to something more appropriate - clean up of uninitialized variables & removal of unneccessary objects - NMesh returns wrapped vectors now - World returns wrapped matrices now - Object.getEuler() and Object.getBoundingBox() return Wrapped data when data is present - Object.getMatrix() returns wrapped data if it's worldspace, 'localspace' returns a new matrix - Vector, Euler, Mat, Quat, call all now internally wrap object without destroying internal datablocks - Removed memory allocation (unneeded) from all methods - Vector's resize methods are only applicable to new vectors not wrapped data. - Matrix(), Quat(), Euler(), Vector() now accepts ANY sequence list, including tuples, list, or a self object to copy - matrices accept multiple sequences - Fixed Slerp() so that it now works correctly values are clamped between 0 and 1 - Euler.rotate does internal rotation now - Slice assignment now works better for all types - Vector * Vector and Quat * Quat are defined and return the DOT product - Mat * Vec and Vec * Mat are defined now - Moved #includes to .c file from headers. Also fixed prototypes in mathutils - Added new helper functions for incref'ing to genutils - Major cleanup of header files includes - include Mathutils.h for access to math types - matrix.toQuat() and .toEuler() now fixed take appropriate matrix sizes - Matrix() with no parameters now returns an identity matrix by default not a zero matrix - printf() now prints with 6 digits instead of 4 - printf() now prints output with object descriptor - Matrices now support [x][y] assignment (e.g. matrix[x][y] = 5.4) - Matrix[index] = value now expectes a sequence not an integer. This will now set a ROW of the matrix through a sequence. index cannot go above the row size of the matrix. - slice operations on matrices work with sequences now (rows of the matrix) example: mymatrix[0:2] returns a list of 2 wrapped vectors with access to the matrix data. - slice assignment will no longer modify the data if the assignment operation fails - fixed error in matrix * scalar multiplication - euler.toMatrix(), toQuat() no longer causes "creep" from repeated use - Wrapped data will generate wrapped objects when toEuler(), toQuat(), toMatrix() is used - Quats can be created with angle/axis, axis/angle - 4x4 matrices can be multiplied by 3D vectors (by popular demand :)) - vec *quat / quat * vec is now defined - vec.magnitude alias for vec.length - all self, internal methods return a pointer to self now so you can do print vector.internalmethod() or vector.internalmethod().nextmethod() (no more print matrix.inverse() returning 'none') - these methods have been deprecated (still functioning but suggested to use the corrected functionality): * CopyVec() - replaced by Vector() functionality * CopyMat() - replaced by Matrix() functionality * CopyQuat() - replace by Quaternion() functionality * CopyEuler() - replaced by Euler() functionality * RotateEuler() - replaced by Euler.rotate() funtionality * MatMultVec() - replaced by matrix * vector * VecMultMat() - replaced by vector * matrix - New struct containers references to python object data or internally allocated blender data for wrapping * Explaination here: math structs now function as a 'simple wrapper' or a 'py_object' - data that is created on the fly will now be a 'py_object' with its memory managed by python * otherwise if the data is returned by blender's G.main then the math object is a 'simple wrapper' and data can be accessed directly from the struct just like other python objects.
Diffstat (limited to 'source/blender/python/api2_2x/quat.c')
-rw-r--r--source/blender/python/api2_2x/quat.c875
1 files changed, 450 insertions, 425 deletions
diff --git a/source/blender/python/api2_2x/quat.c b/source/blender/python/api2_2x/quat.c
index 35ef90aca2d..78944b9f7d5 100644
--- a/source/blender/python/api2_2x/quat.c
+++ b/source/blender/python/api2_2x/quat.c
@@ -29,545 +29,570 @@
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
-#include "quat.h"
-
-//doc strings
-char Quaternion_Identity_doc[] =
- "() - set the quaternion to it's identity (1, vector)";
-char Quaternion_Negate_doc[] =
- "() - set all values in the quaternion to their negative";
+#include "BLI_arithb.h"
+#include "BKE_utildefines.h"
+#include "Mathutils.h"
+#include "gen_utils.h"
+#include "BLI_blenlib.h"
+
+//-------------------------DOC STRINGS ---------------------------
+char Quaternion_Identity_doc[] = "() - set the quaternion to it's identity (1, vector)";
+char Quaternion_Negate_doc[] = "() - set all values in the quaternion to their negative";
char Quaternion_Conjugate_doc[] = "() - set the quaternion to it's conjugate";
char Quaternion_Inverse_doc[] = "() - set the quaternion to it's inverse";
-char Quaternion_Normalize_doc[] =
- "() - normalize the vector portion of the quaternion";
-char Quaternion_ToEuler_doc[] =
- "() - return a euler rotation representing the quaternion";
-char Quaternion_ToMatrix_doc[] =
- "() - return a rotation matrix representing the quaternion";
-
-//methods table
+char Quaternion_Normalize_doc[] = "() - normalize the vector portion of the quaternion";
+char Quaternion_ToEuler_doc[] = "() - return a euler rotation representing the quaternion";
+char Quaternion_ToMatrix_doc[] = "() - return a rotation matrix representing the quaternion";
+//-----------------------METHOD DEFINITIONS ----------------------
struct PyMethodDef Quaternion_methods[] = {
- {"identity", ( PyCFunction ) Quaternion_Identity, METH_NOARGS,
- Quaternion_Identity_doc},
- {"negate", ( PyCFunction ) Quaternion_Negate, METH_NOARGS,
- Quaternion_Negate_doc},
- {"conjugate", ( PyCFunction ) Quaternion_Conjugate, METH_NOARGS,
- Quaternion_Conjugate_doc},
- {"inverse", ( PyCFunction ) Quaternion_Inverse, METH_NOARGS,
- Quaternion_Inverse_doc},
- {"normalize", ( PyCFunction ) Quaternion_Normalize, METH_NOARGS,
- Quaternion_Normalize_doc},
- {"toEuler", ( PyCFunction ) Quaternion_ToEuler, METH_NOARGS,
- Quaternion_ToEuler_doc},
- {"toMatrix", ( PyCFunction ) Quaternion_ToMatrix, METH_NOARGS,
- Quaternion_ToMatrix_doc},
+ {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc},
+ {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc},
+ {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc},
+ {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc},
+ {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc},
+ {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_NOARGS, Quaternion_ToEuler_doc},
+ {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc},
{NULL, NULL, 0, NULL}
};
-
-/* ****** prototypes ********** */
-PyObject *Quaternion_add( PyObject * q1, PyObject * q2 );
-PyObject *Quaternion_sub( PyObject * q1, PyObject * q2 );
-PyObject *Quaternion_mul( PyObject * q1, PyObject * q2 );
-int Quaternion_coerce( PyObject ** q1, PyObject ** q2 );
-
-
-/*****************************/
-// Quaternion Python Object
-/*****************************/
-
-PyObject *Quaternion_ToEuler( QuaternionObject * self )
+//-----------------------------METHODS------------------------------
+//----------------------------Quaternion.toEuler()------------------
+//return the quat as a euler
+PyObject *Quaternion_ToEuler(QuaternionObject * self)
{
- float *eul;
+ float eul[3];
int x;
- eul = PyMem_Malloc( 3 * sizeof( float ) );
- QuatToEul( self->quat, eul );
-
- for( x = 0; x < 3; x++ ) {
- eul[x] *= ( float ) ( 180 / Py_PI );
+ QuatToEul(self->quat, eul);
+ for(x = 0; x < 3; x++) {
+ eul[x] *= (180 / (float)Py_PI);
}
- return ( PyObject * ) newEulerObject( eul );
+ if(self->data.blend_data)
+ return newEulerObject(eul, Py_WRAP);
+ else
+ return newEulerObject(eul, Py_NEW);
}
-
-PyObject *Quaternion_ToMatrix( QuaternionObject * self )
+//----------------------------Quaternion.toMatrix()------------------
+//return the quat as a matrix
+PyObject *Quaternion_ToMatrix(QuaternionObject * self)
{
- float *mat;
-
- mat = PyMem_Malloc( 3 * 3 * sizeof( float ) );
- QuatToMat3( self->quat, ( float ( * )[3] ) mat );
+ float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+ QuatToMat3(self->quat, (float (*)[3]) mat);
- return ( PyObject * ) newMatrixObject( mat, 3, 3 );
+ if(self->data.blend_data)
+ return newMatrixObject(mat, 3, 3, Py_WRAP);
+ else
+ return newMatrixObject(mat, 3, 3, Py_NEW);
}
-
+//----------------------------Quaternion.normalize()----------------
//normalize the axis of rotation of [theta,vector]
-PyObject *Quaternion_Normalize( QuaternionObject * self )
+PyObject *Quaternion_Normalize(QuaternionObject * self)
{
- NormalQuat( self->quat );
- return EXPP_incr_ret( Py_None );
+ NormalQuat(self->quat);
+ return (PyObject*)self;
}
-
-PyObject *Quaternion_Inverse( QuaternionObject * self )
+//----------------------------Quaternion.inverse()------------------
+//invert the quat
+PyObject *Quaternion_Inverse(QuaternionObject * self)
{
- float mag = 0.0f;
+ double mag = 0.0f;
int x;
- for( x = 1; x < 4; x++ ) {
+ for(x = 1; x < 4; x++) {
self->quat[x] = -self->quat[x];
}
- for( x = 0; x < 4; x++ ) {
- mag += ( self->quat[x] * self->quat[x] );
+ for(x = 0; x < 4; x++) {
+ mag += (self->quat[x] * self->quat[x]);
}
- mag = ( float ) sqrt( mag );
- for( x = 0; x < 4; x++ ) {
- self->quat[x] /= ( mag * mag );
+ mag = sqrt(mag);
+ for(x = 0; x < 4; x++) {
+ self->quat[x] /= (mag * mag);
}
- return EXPP_incr_ret( Py_None );
+ return (PyObject*)self;
}
-
-PyObject *Quaternion_Identity( QuaternionObject * self )
+//----------------------------Quaternion.identity()-----------------
+//generate the identity quaternion
+PyObject *Quaternion_Identity(QuaternionObject * self)
{
self->quat[0] = 1.0;
self->quat[1] = 0.0;
self->quat[2] = 0.0;
self->quat[3] = 0.0;
- return EXPP_incr_ret( Py_None );
+ return (PyObject*)self;
}
-
-PyObject *Quaternion_Negate( QuaternionObject * self )
+//----------------------------Quaternion.negate()-------------------
+//negate the quat
+PyObject *Quaternion_Negate(QuaternionObject * self)
{
int x;
-
- for( x = 0; x < 4; x++ ) {
+ for(x = 0; x < 4; x++) {
self->quat[x] = -self->quat[x];
}
- return EXPP_incr_ret( Py_None );
+ return (PyObject*)self;
}
-
-PyObject *Quaternion_Conjugate( QuaternionObject * self )
+//----------------------------Quaternion.conjugate()----------------
+//negate the vector part
+PyObject *Quaternion_Conjugate(QuaternionObject * self)
{
int x;
-
- for( x = 1; x < 4; x++ ) {
+ for(x = 1; x < 4; x++) {
self->quat[x] = -self->quat[x];
}
- return EXPP_incr_ret( Py_None );
+ return (PyObject*)self;
}
-
-static void Quaternion_dealloc( QuaternionObject * self )
+//----------------------------dealloc()(internal) ------------------
+//free the py_object
+static void Quaternion_dealloc(QuaternionObject * self)
{
- PyMem_Free( self->quat );
- PyObject_DEL( self );
+ //only free py_data
+ if(self->data.py_data){
+ PyMem_Free(self->data.py_data);
+ }
+ PyObject_DEL(self);
}
-
-static PyObject *Quaternion_getattr( QuaternionObject * self, char *name )
+//----------------------------getattr()(internal) ------------------
+//object.attribute access (get)
+static PyObject *Quaternion_getattr(QuaternionObject * self, char *name)
{
- double mag = 0.0f;
- float *vec = NULL;
int x;
- PyObject *retval;
-
- if( ELEM4( name[0], 'w', 'x', 'y', 'z' ) && name[1] == 0 ) {
- return PyFloat_FromDouble( self->quat[name[0] - 'w'] );
+ double mag = 0.0f;
+ float vec[3];
+
+ if(STREQ(name,"w")){
+ return PyFloat_FromDouble(self->quat[0]);
+ }else if(STREQ(name, "x")){
+ return PyFloat_FromDouble(self->quat[1]);
+ }else if(STREQ(name, "y")){
+ return PyFloat_FromDouble(self->quat[2]);
+ }else if(STREQ(name, "z")){
+ return PyFloat_FromDouble(self->quat[3]);
}
- if( strcmp( name, "magnitude" ) == 0 ) {
- for( x = 0; x < 4; x++ ) {
+ if(STREQ(name, "magnitude")) {
+ for(x = 0; x < 4; x++) {
mag += self->quat[x] * self->quat[x];
}
- mag = ( float ) sqrt( mag );
- return PyFloat_FromDouble( mag );
+ mag = sqrt(mag);
+ return PyFloat_FromDouble(mag);
}
- if( strcmp( name, "angle" ) == 0 ) {
-
+ if(STREQ(name, "angle")) {
mag = self->quat[0];
- mag = 2 * ( acos( mag ) );
- mag *= ( 180 / Py_PI );
- return PyFloat_FromDouble( mag );
+ mag = 2 * (acos(mag));
+ mag *= (180 / Py_PI);
+ return PyFloat_FromDouble(mag);
}
- if( strcmp( name, "axis" ) == 0 ) {
-
- mag = ( double ) ( self->quat[0] * ( Py_PI / 180 ) );
- mag = 2 * ( acos( mag ) );
- mag = sin( mag / 2 );
- vec = PyMem_Malloc( 3 * sizeof( float ) );
- for( x = 0; x < 3; x++ ) {
- vec[x] = ( self->quat[x + 1] / ( ( float ) ( mag ) ) );
+ if(STREQ(name, "axis")) {
+ mag = self->quat[0] * (Py_PI / 180);
+ mag = 2 * (acos(mag));
+ mag = sin(mag / 2);
+ for(x = 0; x < 3; x++) {
+ vec[x] = (self->quat[x + 1] / mag);
}
- Normalise( vec );
- retval = ( PyObject * ) newVectorObject( vec, 3 );
- PyMem_Free( vec );
- return retval;
+ Normalise(vec);
+ return (PyObject *) newVectorObject(vec, 3, Py_NEW);
}
- return Py_FindMethod( Quaternion_methods, ( PyObject * ) self, name );
-}
-static int Quaternion_setattr( QuaternionObject * self, char *name,
- PyObject * v )
+ return Py_FindMethod(Quaternion_methods, (PyObject *) self, name);
+}
+//----------------------------setattr()(internal) ------------------
+//object.attribute access (set)
+static int Quaternion_setattr(QuaternionObject * self, char *name, PyObject * q)
{
- float val;
-
- if( !PyFloat_Check( v ) && !PyInt_Check( v ) ) {
- return EXPP_ReturnIntError( PyExc_TypeError,
- "int or float expected\n" );
- } else {
- if( !PyArg_Parse( v, "f", &val ) )
- return EXPP_ReturnIntError( PyExc_TypeError,
- "unable to parse float argument\n" );
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(q);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion.attribute = x: argument not a number\n");
+ }
+
+ if(STREQ(name,"w")){
+ self->quat[0] = PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "x")){
+ self->quat[1] = PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "y")){
+ self->quat[2] = PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "z")){
+ self->quat[3] = PyFloat_AS_DOUBLE(f);
+ }else{
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "quaternion.attribute = x: unknown attribute\n");
}
- if( ELEM4( name[0], 'w', 'x', 'y', 'z' ) && name[1] == 0 ) {
- self->quat[name[0] - 'w'] = val;
- } else
- return -1;
+ Py_DECREF(f);
return 0;
}
-
-/* Quaternions Sequence methods */
-static PyObject *Quaternion_item( QuaternionObject * self, int i )
+//----------------------------print object (internal)--------------
+//print the object to screen
+static PyObject *Quaternion_repr(QuaternionObject * self)
{
- if( i < 0 || i >= 4 )
- return EXPP_ReturnPyObjError( PyExc_IndexError,
- "array index out of range\n" );
+ int i;
+ char buffer[48], str[1024];
+
+ BLI_strncpy(str,"[",1024);
+ for(i = 0; i < 4; i++){
+ if(i < (3)){
+ sprintf(buffer, "%.6f, ", self->quat[i]);
+ strcat(str,buffer);
+ }else{
+ sprintf(buffer, "%.6f", self->quat[i]);
+ strcat(str,buffer);
+ }
+ }
+ strcat(str, "](quaternion)");
- return Py_BuildValue( "f", self->quat[i] );
+ return EXPP_incr_ret(PyString_FromString(str));
}
-
-static PyObject *Quaternion_slice( QuaternionObject * self, int begin,
- int end )
+//---------------------SEQUENCE PROTOCOLS------------------------
+//----------------------------len(object)------------------------
+//sequence length
+static int Quaternion_len(QuaternionObject * self)
{
- PyObject *list;
- int count;
-
- if( begin < 0 )
- begin = 0;
- if( end > 4 )
- end = 4;
- if( begin > end )
- begin = end;
+ return 4;
+}
+//----------------------------object[]---------------------------
+//sequence accessor (get)
+static PyObject *Quaternion_item(QuaternionObject * self, int i)
+{
+ if(i < 0 || i >= 4)
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "quaternion[attribute]: array index out of range\n");
- list = PyList_New( end - begin );
+ return Py_BuildValue("f", self->quat[i]);
- for( count = begin; count < end; count++ ) {
- PyList_SetItem( list, count - begin,
- PyFloat_FromDouble( self->quat[count] ) );
- }
- return list;
}
-
-static int Quaternion_ass_item( QuaternionObject * self, int i, PyObject * ob )
+//----------------------------object[]-------------------------
+//sequence accessor (set)
+static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
{
- if( i < 0 || i >= 4 )
- return EXPP_ReturnIntError( PyExc_IndexError,
- "array assignment index out of range\n" );
- if( !PyNumber_Check( ob ) )
- return EXPP_ReturnIntError( PyExc_IndexError,
- "Quaternion member must be a number\n" );
-
- if( !PyFloat_Check( ob ) && !PyInt_Check( ob ) ) {
- return EXPP_ReturnIntError( PyExc_TypeError,
- "int or float expected\n" );
- } else {
- self->quat[i] = ( float ) PyFloat_AsDouble( ob );
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(ob);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion[attribute] = x: argument not a number\n");
}
- return 0;
-}
-static int Quaternion_ass_slice( QuaternionObject * self, int begin, int end,
- PyObject * seq )
-{
- int count, z;
-
- if( begin < 0 )
- begin = 0;
- if( end > 4 )
- end = 4;
- if( begin > end )
- begin = end;
-
- if( !PySequence_Check( seq ) )
- return EXPP_ReturnIntError( PyExc_TypeError,
- "illegal argument type for built-in operation\n" );
- if( PySequence_Length( seq ) != ( end - begin ) )
- return EXPP_ReturnIntError( PyExc_TypeError,
- "size mismatch in slice assignment\n" );
-
- z = 0;
- for( count = begin; count < end; count++ ) {
- PyObject *ob = PySequence_GetItem( seq, z );
- z++;
-
- if( !PyFloat_Check( ob ) && !PyInt_Check( ob ) ) {
- Py_DECREF( ob );
- return -1;
- } else {
- if( !PyArg_Parse( ob, "f", &self->quat[count] ) ) {
- Py_DECREF( ob );
- return -1;
- }
- }
+ if(i < 0 || i >= 4){
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_IndexError,
+ "quaternion[attribute] = x: array assignment index out of range\n");
}
+ self->quat[i] = PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
return 0;
}
-
-static PyObject *Quaternion_repr( QuaternionObject * self )
+//----------------------------object[z:y]------------------------
+//sequence slice (get)
+static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
{
- int i, maxindex = 4 - 1;
- char ftoa[24];
- PyObject *str1, *str2;
-
- str1 = PyString_FromString( "[" );
-
- for( i = 0; i < maxindex; i++ ) {
- sprintf( ftoa, "%.4f, ", self->quat[i] );
- str2 = PyString_FromString( ftoa );
- if( !str1 || !str2 )
- goto error;
- PyString_ConcatAndDel( &str1, str2 );
- }
+ PyObject *list = NULL;
+ int count;
- sprintf( ftoa, "%.4f]", self->quat[maxindex] );
- str2 = PyString_FromString( ftoa );
- if( !str1 || !str2 )
- goto error;
- PyString_ConcatAndDel( &str1, str2 );
+ CLAMP(begin, 0, 4);
+ CLAMP(end, 0, 4);
+ begin = MIN2(begin,end);
- if( str1 )
- return str1;
+ list = PyList_New(end - begin);
+ for(count = begin; count < end; count++) {
+ PyList_SetItem(list, count - begin,
+ PyFloat_FromDouble(self->quat[count]));
+ }
- error:
- Py_XDECREF( str1 );
- Py_XDECREF( str2 );
- return EXPP_ReturnPyObjError( PyExc_MemoryError,
- "couldn't create PyString!\n" );
+ return list;
}
-
-
-PyObject *Quaternion_add( PyObject * q1, PyObject * q2 )
+//----------------------------object[z:y]------------------------
+//sequence slice (set)
+static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end,
+ PyObject * seq)
{
- float *quat = NULL;
- PyObject *retval;
- int x;
+ int i, y, size = 0;
+ float quat[4];
- if( ( !QuaternionObject_Check( q1 ) )
- || ( !QuaternionObject_Check( q2 ) ) )
- return EXPP_ReturnPyObjError( PyExc_TypeError,
- "unsupported type for this operation\n" );
- if( ( ( QuaternionObject * ) q1 )->flag > 0
- || ( ( QuaternionObject * ) q2 )->flag > 0 )
- return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
- "cannot add a scalar and a quat\n" );
-
- quat = PyMem_Malloc( 4 * sizeof( float ) );
- for( x = 0; x < 4; x++ ) {
- quat[x] =
- ( ( ( QuaternionObject * ) q1 )->quat[x] ) +
- ( ( ( QuaternionObject * ) q2 )->quat[x] );
+ CLAMP(begin, 0, 4);
+ CLAMP(end, 0, 4);
+ begin = MIN2(begin,end);
+
+ size = PySequence_Length(seq);
+ if(size != (end - begin)){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion[begin:end] = []: size mismatch in slice assignment\n");
}
- retval = ( PyObject * ) newQuaternionObject( quat );
- PyMem_Free( quat );
- return retval;
-}
+ for (i = 0; i < size; i++) {
+ PyObject *q, *f;
-PyObject *Quaternion_sub( PyObject * q1, PyObject * q2 )
+ q = PySequence_GetItem(seq, i);
+ if (q == NULL) { // Failed to read sequence
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "quaternion[begin:end] = []: unable to read sequence\n");
+ }
+ f = PyNumber_Float(q);
+ if(f == NULL) { // parsed item not a number
+ Py_DECREF(q);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion[begin:end] = []: sequence argument not a number\n");
+ }
+ quat[i] = PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,q);
+ }
+ //parsed well - now set in vector
+ for(y = 0; y < size; y++){
+ self->quat[begin + y] = quat[y];
+ }
+ return 0;
+}
+//------------------------NUMERIC PROTOCOLS----------------------
+//------------------------obj + obj------------------------------
+//addition
+static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
{
- float *quat = NULL;
- PyObject *retval;
int x;
+ float quat[4];
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ EXPP_incr2(q1, q2);
+ quat1 = (QuaternionObject*)q1;
+ quat2 = (QuaternionObject*)q2;
- if( ( !QuaternionObject_Check( q1 ) )
- || ( !QuaternionObject_Check( q2 ) ) )
- return EXPP_ReturnPyObjError( PyExc_TypeError,
- "unsupported type for this operation\n" );
- if( ( ( QuaternionObject * ) q1 )->flag > 0
- || ( ( QuaternionObject * ) q2 )->flag > 0 )
- return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
- "cannot subtract a scalar and a quat\n" );
-
- quat = PyMem_Malloc( 4 * sizeof( float ) );
- for( x = 0; x < 4; x++ ) {
- quat[x] =
- ( ( ( QuaternionObject * ) q1 )->quat[x] ) -
- ( ( ( QuaternionObject * ) q2 )->quat[x] );
+ if(quat1->coerced_object || quat2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Quaternion addition: arguments not valid for this operation....\n");
+ }
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat1->quat[x] + quat2->quat[x];
}
- retval = ( PyObject * ) newQuaternionObject( quat );
- PyMem_Free( quat );
- return retval;
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return (PyObject *) newQuaternionObject(quat, Py_NEW);
}
-
-PyObject *Quaternion_mul( PyObject * q1, PyObject * q2 )
+//------------------------obj - obj------------------------------
+//subtraction
+static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
{
- float *quat = NULL;
- PyObject *retval;
int x;
+ float quat[4];
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ EXPP_incr2(q1, q2);
+ quat1 = (QuaternionObject*)q1;
+ quat2 = (QuaternionObject*)q2;
- if( ( !QuaternionObject_Check( q1 ) )
- || ( !QuaternionObject_Check( q2 ) ) )
- return EXPP_ReturnPyObjError( PyExc_TypeError,
- "unsupported type for this operation\n" );
- if( ( ( QuaternionObject * ) q1 )->flag == 0
- && ( ( QuaternionObject * ) q2 )->flag == 0 )
- return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
- "please use the dot or cross product to multiply quaternions\n" );
-
- quat = PyMem_Malloc( 4 * sizeof( float ) );
- //scalar mult by quat
- for( x = 0; x < 4; x++ ) {
- quat[x] =
- ( ( QuaternionObject * ) q1 )->quat[x] *
- ( ( QuaternionObject * ) q2 )->quat[x];
+ if(quat1->coerced_object || quat2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Quaternion addition: arguments not valid for this operation....\n");
+ }
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat1->quat[x] - quat2->quat[x];
}
- retval = ( PyObject * ) newQuaternionObject( quat );
- PyMem_Free( quat );
- return retval;
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return (PyObject *) newQuaternionObject(quat, Py_NEW);
}
-
-//coercion of unknown types to type QuaternionObject for numeric protocols
-int Quaternion_coerce( PyObject ** q1, PyObject ** q2 )
+//------------------------obj * obj------------------------------
+//mulplication
+static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
{
- long *tempI = NULL;
- double *tempF = NULL;
- float *quat = NULL;
int x;
-
- if( QuaternionObject_Check( *q1 ) ) {
- if( QuaternionObject_Check( *q2 ) ) { //two Quaternions
- Py_INCREF( *q1 );
- Py_INCREF( *q2 );
- return 0;
- } else {
- if( PyNumber_Check( *q2 ) ) {
- if( PyInt_Check( *q2 ) ) { //cast scalar to Quaternion
- tempI = PyMem_Malloc( 1 *
- sizeof( long ) );
- *tempI = PyInt_AsLong( *q2 );
- quat = PyMem_Malloc( 4 *
- sizeof( float ) );
- for( x = 0; x < 4; x++ ) {
- quat[x] = ( float ) *tempI;
- }
- PyMem_Free( tempI );
- *q2 = newQuaternionObject( quat );
- PyMem_Free( quat );
- ( ( QuaternionObject * ) * q2 )->flag = 1; //int coercion
- Py_INCREF( *q1 ); /* fixme: is this needed? */
- return 0;
- } else if( PyFloat_Check( *q2 ) ) { //cast scalar to Quaternion
- tempF = PyMem_Malloc( 1 *
- sizeof
- ( double ) );
- *tempF = PyFloat_AsDouble( *q2 );
- quat = PyMem_Malloc( 4 *
- sizeof( float ) );
- for( x = 0; x < 4; x++ ) {
- quat[x] = ( float ) *tempF;
- }
- PyMem_Free( tempF );
- *q2 = newQuaternionObject( quat );
- PyMem_Free( quat );
- ( ( QuaternionObject * ) * q2 )->flag = 2; //float coercion
- Py_INCREF( *q1 ); /* fixme: is this needed? */
- return 0;
+ float quat[4], scalar, newVec[3];
+ double dot = 0.0f;
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+ PyObject *f = NULL;
+ VectorObject *vec = NULL;
+
+ EXPP_incr2(q1, q2);
+ quat1 = (QuaternionObject*)q1;
+ quat2 = (QuaternionObject*)q2;
+
+ if(quat1->coerced_object){
+ if (PyFloat_Check(quat1->coerced_object) ||
+ PyInt_Check(quat1->coerced_object)){ // FLOAT/INT * QUAT
+ f = PyNumber_Float(quat1->coerced_object);
+ if(f == NULL) { // parsed item not a number
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: arguments not acceptable for this operation\n");
+ }
+ scalar = PyFloat_AS_DOUBLE(f);
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat2->quat[x] * scalar;
+ }
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return (PyObject *) newQuaternionObject(quat, Py_NEW);
+ }
+ }else{
+ if(quat2->coerced_object){
+ if (PyFloat_Check(quat2->coerced_object) ||
+ PyInt_Check(quat2->coerced_object)){ // QUAT * FLOAT/INT
+ f = PyNumber_Float(quat2->coerced_object);
+ if(f == NULL) { // parsed item not a number
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: arguments not acceptable for this operation\n");
+ }
+ scalar = PyFloat_AS_DOUBLE(f);
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat1->quat[x] * scalar;
+ }
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return (PyObject *) newQuaternionObject(quat, Py_NEW);
+ }else if(VectorObject_Check(quat2->coerced_object)){ //QUAT * VEC
+ vec = (VectorObject*)EXPP_incr_ret(quat2->coerced_object);
+ if(vec->size != 3){
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: only 3D vector rotations currently supported\n");
}
+ newVec[0] = quat1->quat[0]*quat1->quat[0]*vec->vec[0] +
+ 2*quat1->quat[2]*quat1->quat[0]*vec->vec[2] -
+ 2*quat1->quat[3]*quat1->quat[0]*vec->vec[1] +
+ quat1->quat[1]*quat1->quat[1]*vec->vec[0] +
+ 2*quat1->quat[2]*quat1->quat[1]*vec->vec[1] +
+ 2*quat1->quat[3]*quat1->quat[1]*vec->vec[2] -
+ quat1->quat[3]*quat1->quat[3]*vec->vec[0] -
+ quat1->quat[2]*quat1->quat[2]*vec->vec[0];
+ newVec[1] = 2*quat1->quat[1]*quat1->quat[2]*vec->vec[0] +
+ quat1->quat[2]*quat1->quat[2]*vec->vec[1] +
+ 2*quat1->quat[3]*quat1->quat[2]*vec->vec[2] +
+ 2*quat1->quat[0]*quat1->quat[3]*vec->vec[0] -
+ quat1->quat[3]*quat1->quat[3]*vec->vec[1] +
+ quat1->quat[0]*quat1->quat[0]*vec->vec[1] -
+ 2*quat1->quat[1]*quat1->quat[0]*vec->vec[2] -
+ quat1->quat[1]*quat1->quat[1]*vec->vec[1];
+ newVec[2] = 2*quat1->quat[1]*quat1->quat[3]*vec->vec[0] +
+ 2*quat1->quat[2]*quat1->quat[3]*vec->vec[1] +
+ quat1->quat[3]*quat1->quat[3]*vec->vec[2] -
+ 2*quat1->quat[0]*quat1->quat[2]*vec->vec[0] -
+ quat1->quat[2]*quat1->quat[2]*vec->vec[2] +
+ 2*quat1->quat[0]*quat1->quat[1]*vec->vec[1] -
+ quat1->quat[1]*quat1->quat[1]*vec->vec[2] +
+ quat1->quat[0]*quat1->quat[0]*vec->vec[2];
+ EXPP_decr3((PyObject*)quat1, (PyObject*)quat2, (PyObject*)vec);
+ return newVectorObject(newVec,3,Py_NEW);
}
- //unknown type or numeric cast failure
- printf( "attempting quaternion operation with unsupported type...\n" );
- Py_INCREF( *q1 ); /* fixme: is this needed? */
- return 0; //operation will type check
+ }else{ //QUAT * QUAT (dot product)
+ for(x = 0; x < 4; x++) {
+ dot += quat1->quat[x] * quat1->quat[x];
+ }
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return PyFloat_FromDouble(dot);
}
- } else {
- printf( "numeric protocol failure...\n" );
- return -1; //this should not occur - fail
}
- return -1;
-}
+ EXPP_decr2((PyObject*)quat1, (PyObject*)quat2);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: arguments not acceptable for this operation\n");
+}
+//------------------------coerce(obj, obj)-----------------------
+//coercion of unknown types to type QuaternionObject for numeric protocols
+/*Coercion() is called whenever a math operation has 2 operands that
+ it doesn't understand how to evaluate. 2+Matrix for example. We want to
+ evaluate some of these operations like: (vector * 2), however, for math
+ to proceed, the unknown operand must be cast to a type that python math will
+ understand. (e.g. in the case above case, 2 must be cast to a vector and
+ then call vector.multiply(vector, scalar_cast_as_vector)*/
+static int Quaternion_coerce(PyObject ** q1, PyObject ** q2)
+{
+ PyObject *coerced = NULL;
+
+ if(!QuaternionObject_Check(*q2)) {
+ if(VectorObject_Check(*q2) || PyFloat_Check(*q2) || PyInt_Check(*q2)) {
+ coerced = EXPP_incr_ret(*q2);
+ *q2 = newQuaternionObject(NULL,Py_NEW);
+ ((QuaternionObject*)*q2)->coerced_object = coerced;
+ }else{
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion.coerce(): unknown operand - can't coerce for numeric protocols\n");
+ }
+ }
+ EXPP_incr2(*q1, *q2);
+ return 0;
+}
+//-----------------PROTCOL DECLARATIONS--------------------------
static PySequenceMethods Quaternion_SeqMethods = {
- ( inquiry ) 0, /* sq_length */
- ( binaryfunc ) 0, /* sq_concat */
- ( intargfunc ) 0, /* sq_repeat */
- ( intargfunc ) Quaternion_item, /* sq_item */
- ( intintargfunc ) Quaternion_slice, /* sq_slice */
- ( intobjargproc ) Quaternion_ass_item, /* sq_ass_item */
- ( intintobjargproc ) Quaternion_ass_slice, /* sq_ass_slice */
+ (inquiry) Quaternion_len, /* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) Quaternion_item, /* sq_item */
+ (intintargfunc) Quaternion_slice, /* sq_slice */
+ (intobjargproc) Quaternion_ass_item, /* sq_ass_item */
+ (intintobjargproc) Quaternion_ass_slice, /* sq_ass_slice */
};
-
static PyNumberMethods Quaternion_NumMethods = {
- ( binaryfunc ) Quaternion_add, /* __add__ */
- ( binaryfunc ) Quaternion_sub, /* __sub__ */
- ( binaryfunc ) Quaternion_mul, /* __mul__ */
- ( binaryfunc ) 0, /* __div__ */
- ( binaryfunc ) 0, /* __mod__ */
- ( binaryfunc ) 0, /* __divmod__ */
- ( ternaryfunc ) 0, /* __pow__ */
- ( unaryfunc ) 0, /* __neg__ */
- ( unaryfunc ) 0, /* __pos__ */
- ( unaryfunc ) 0, /* __abs__ */
- ( inquiry ) 0, /* __nonzero__ */
- ( unaryfunc ) 0, /* __invert__ */
- ( binaryfunc ) 0, /* __lshift__ */
- ( binaryfunc ) 0, /* __rshift__ */
- ( binaryfunc ) 0, /* __and__ */
- ( binaryfunc ) 0, /* __xor__ */
- ( binaryfunc ) 0, /* __or__ */
- ( coercion ) Quaternion_coerce, /* __coerce__ */
- ( unaryfunc ) 0, /* __int__ */
- ( unaryfunc ) 0, /* __long__ */
- ( unaryfunc ) 0, /* __float__ */
- ( unaryfunc ) 0, /* __oct__ */
- ( unaryfunc ) 0, /* __hex__ */
+ (binaryfunc) Quaternion_add, /* __add__ */
+ (binaryfunc) Quaternion_sub, /* __sub__ */
+ (binaryfunc) Quaternion_mul, /* __mul__ */
+ (binaryfunc) 0, /* __div__ */
+ (binaryfunc) 0, /* __mod__ */
+ (binaryfunc) 0, /* __divmod__ */
+ (ternaryfunc) 0, /* __pow__ */
+ (unaryfunc) 0, /* __neg__ */
+ (unaryfunc) 0, /* __pos__ */
+ (unaryfunc) 0, /* __abs__ */
+ (inquiry) 0, /* __nonzero__ */
+ (unaryfunc) 0, /* __invert__ */
+ (binaryfunc) 0, /* __lshift__ */
+ (binaryfunc) 0, /* __rshift__ */
+ (binaryfunc) 0, /* __and__ */
+ (binaryfunc) 0, /* __xor__ */
+ (binaryfunc) 0, /* __or__ */
+ (coercion) Quaternion_coerce, /* __coerce__ */
+ (unaryfunc) 0, /* __int__ */
+ (unaryfunc) 0, /* __long__ */
+ (unaryfunc) 0, /* __float__ */
+ (unaryfunc) 0, /* __oct__ */
+ (unaryfunc) 0, /* __hex__ */
};
-
+//------------------PY_OBECT DEFINITION--------------------------
PyTypeObject quaternion_Type = {
- PyObject_HEAD_INIT( NULL )
- 0, /*ob_size */
- "quaternion", /*tp_name */
- sizeof( QuaternionObject ), /*tp_basicsize */
- 0, /*tp_itemsize */
- ( destructor ) Quaternion_dealloc, /*tp_dealloc */
- ( printfunc ) 0, /*tp_print */
- ( getattrfunc ) Quaternion_getattr, /*tp_getattr */
- ( setattrfunc ) Quaternion_setattr, /*tp_setattr */
- 0, /*tp_compare */
- ( reprfunc ) Quaternion_repr, /*tp_repr */
- &Quaternion_NumMethods, /*tp_as_number */
- &Quaternion_SeqMethods, /*tp_as_sequence */
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size */
+ "quaternion", /*tp_name */
+ sizeof(QuaternionObject), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ (destructor) Quaternion_dealloc, /*tp_dealloc */
+ (printfunc) 0, /*tp_print */
+ (getattrfunc) Quaternion_getattr, /*tp_getattr */
+ (setattrfunc) Quaternion_setattr, /*tp_setattr */
+ 0, /*tp_compare */
+ (reprfunc) Quaternion_repr, /*tp_repr */
+ &Quaternion_NumMethods, /*tp_as_number */
+ &Quaternion_SeqMethods, /*tp_as_sequence */
};
-
-/** Creates a new quaternion object.
- *
- * Memory for a new quaternion is allocated. The quaternion copies the given
- * list of parameters or initializes to the identity, if a <code>NULL</code>
- * pointer is given as parameter. The memory will be freed in the dealloc
- * routine.
- *
- * @param quat Pointer to a list of floats for the quanternion parameters w, x, y, z.
- * @return Quaternion Python object.
- * @see Quaternion_Identity
- */
-PyObject *newQuaternionObject( float *quat )
+//------------------------newQuaternionObject (internal)-------------
+//creates a new quaternion object
+/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
+ (i.e. it was allocated elsewhere by MEM_mallocN())
+ pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
+ (i.e. it must be created here with PyMEM_malloc())*/
+PyObject *newQuaternionObject(float *quat, int type)
{
QuaternionObject *self;
int x;
quaternion_Type.ob_type = &PyType_Type;
-
- self = PyObject_NEW( QuaternionObject, &quaternion_Type );
-
- self->quat = PyMem_Malloc( 4 * sizeof( float ) );
-
- if( !quat ) {
- Quaternion_Identity(self);
- } else {
- for( x = 0; x < 4; x++ ) {
- self->quat[x] = quat[x];
+ self = PyObject_NEW(QuaternionObject, &quaternion_Type);
+ self->data.blend_data = NULL;
+ self->data.py_data = NULL;
+ self->coerced_object = NULL;
+
+ if(type == Py_WRAP){
+ self->data.blend_data = quat;
+ self->quat = self->data.blend_data;
+ }else if (type == Py_NEW){
+ self->data.py_data = PyMem_Malloc(4 * sizeof(float));
+ self->quat = self->data.py_data;
+ if(!quat) { //new empty
+ Quaternion_Identity(self);
+ }else{
+ for(x = 0; x < 4; x++){
+ self->quat[x] = quat[x];
+ }
}
+ }else{ //bad type
+ return NULL;
}
- self->flag = 0;
-
- return ( PyObject * ) self;
+ return (PyObject *) EXPP_incr_ret((PyObject *)self);
}