This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/python/api2_2x/Mathutils.c

1626 lines
49 KiB
C
Raw Normal View History

/*
* $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. The Blender
* Foundation also sells licenses for use in proprietary software under
* the Blender License. See http://www.blender.org/BL/ for information
* about this.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* This is a new part of Blender.
*
* Contributor(s): Joseph Gilbert, Campbell Barton
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include <Python.h>
#include <BKE_main.h>
#include <BKE_global.h>
#include <BKE_library.h>
#include <BKE_utildefines.h>
#include <BLI_blenlib.h>
#include <BLI_arithb.h>
#include <PIL_time.h>
#include <BLI_rand.h>
#include <math.h>
#include "vector.h"
#include "euler.h"
#include "quat.h"
#include "matrix.h"
#include "blendef.h"
#include "mydevice.h"
#include "constant.h"
#include "gen_utils.h"
#include "Mathutils.h"
/*****************************************************************************/
// Python API function prototypes for the Mathutils module.
/*****************************************************************************/
static PyObject *M_Mathutils_Rand( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Vector( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CrossVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_DotVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_AngleBetweenVecs( PyObject * self,
PyObject * args );
static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyVec( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Matrix( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_RotationMatrix( PyObject * self,
PyObject * args );
static PyObject *M_Mathutils_ScaleMatrix( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_OrthoProjectionMatrix( PyObject * self,
PyObject * args );
static PyObject *M_Mathutils_ShearMatrix( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_TranslationMatrix( PyObject * self,
PyObject * args );
static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_DifferenceQuats( PyObject * self,
PyObject * args );
static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyEuler( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args );
/*****************************************************************************/
// The following string definitions are used for documentation strings.
// In Python these will be written to the console when doing a
// Blender.Mathutils.__doc__
/* Mathutils Module strings */
/****************************************************************************/
static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
static char M_Mathutils_Vector_doc[] =
"() - create a new vector object from a list of floats";
static char M_Mathutils_Matrix_doc[] =
"() - create a new matrix object from a list of floats";
static char M_Mathutils_Quaternion_doc[] =
"() - create a quaternion from a list or an axis of rotation and an angle";
static char M_Mathutils_Euler_doc[] =
"() - create and return a new euler object";
static char M_Mathutils_Rand_doc[] = "() - return a random number";
static char M_Mathutils_CrossVecs_doc[] =
"() - returns a vector perpedicular to the 2 vectors crossed";
static char M_Mathutils_CopyVec_doc[] = "() - create a copy of vector";
static char M_Mathutils_DotVecs_doc[] =
"() - return the dot product of two vectors";
static char M_Mathutils_AngleBetweenVecs_doc[] =
"() - returns the angle between two vectors in degrees";
static char M_Mathutils_MidpointVecs_doc[] =
"() - return the vector to the midpoint between two vectors";
static char M_Mathutils_MatMultVec_doc[] =
"() - multiplies a matrix by a column vector";
static char M_Mathutils_VecMultMat_doc[] =
"() - multiplies a row vector by a matrix";
static char M_Mathutils_ProjectVecs_doc[] =
"() - returns the projection vector from the projection of vecA onto vecB";
static char M_Mathutils_RotationMatrix_doc[] =
"() - construct a rotation matrix from an angle and axis of rotation";
static char M_Mathutils_ScaleMatrix_doc[] =
"() - construct a scaling matrix from a scaling factor";
static char M_Mathutils_OrthoProjectionMatrix_doc[] =
"() - construct a orthographic projection matrix from a selected plane";
static char M_Mathutils_ShearMatrix_doc[] =
"() - construct a shearing matrix from a plane of shear and a shear factor";
static char M_Mathutils_CopyMat_doc[] = "() - create a copy of a matrix";
static char M_Mathutils_TranslationMatrix_doc[] =
"() - create a translation matrix from a vector";
static char M_Mathutils_CopyQuat_doc[] = "() - copy quatB to quatA";
static char M_Mathutils_CopyEuler_doc[] = "() - copy eulB to eultA";
static char M_Mathutils_CrossQuats_doc[] =
"() - return the mutliplication of two quaternions";
static char M_Mathutils_DotQuats_doc[] =
"() - return the dot product of two quaternions";
static char M_Mathutils_Slerp_doc[] =
"() - returns the interpolation between two quaternions";
static char M_Mathutils_DifferenceQuats_doc[] =
"() - return the angular displacment difference between two quats";
static char M_Mathutils_RotateEuler_doc[] =
"() - rotate euler by an axis and angle";
/****************************************************************************/
// Python method structure definition for Blender.Mathutils module:
/****************************************************************************/
struct PyMethodDef M_Mathutils_methods[] = {
{"Rand", ( PyCFunction ) M_Mathutils_Rand, METH_VARARGS,
M_Mathutils_Rand_doc},
{"Vector", ( PyCFunction ) M_Mathutils_Vector, METH_VARARGS,
M_Mathutils_Vector_doc},
{"CrossVecs", ( PyCFunction ) M_Mathutils_CrossVecs, METH_VARARGS,
M_Mathutils_CrossVecs_doc},
{"DotVecs", ( PyCFunction ) M_Mathutils_DotVecs, METH_VARARGS,
M_Mathutils_DotVecs_doc},
{"AngleBetweenVecs", ( PyCFunction ) M_Mathutils_AngleBetweenVecs,
METH_VARARGS,
M_Mathutils_AngleBetweenVecs_doc},
{"MidpointVecs", ( PyCFunction ) M_Mathutils_MidpointVecs,
METH_VARARGS,
M_Mathutils_MidpointVecs_doc},
{"VecMultMat", ( PyCFunction ) M_Mathutils_VecMultMat, METH_VARARGS,
M_Mathutils_VecMultMat_doc},
{"ProjectVecs", ( PyCFunction ) M_Mathutils_ProjectVecs, METH_VARARGS,
M_Mathutils_ProjectVecs_doc},
{"CopyVec", ( PyCFunction ) M_Mathutils_CopyVec, METH_VARARGS,
M_Mathutils_CopyVec_doc},
{"Matrix", ( PyCFunction ) M_Mathutils_Matrix, METH_VARARGS,
M_Mathutils_Matrix_doc},
{"RotationMatrix", ( PyCFunction ) M_Mathutils_RotationMatrix,
METH_VARARGS,
M_Mathutils_RotationMatrix_doc},
{"ScaleMatrix", ( PyCFunction ) M_Mathutils_ScaleMatrix, METH_VARARGS,
M_Mathutils_ScaleMatrix_doc},
{"ShearMatrix", ( PyCFunction ) M_Mathutils_ShearMatrix, METH_VARARGS,
M_Mathutils_ShearMatrix_doc},
{"TranslationMatrix", ( PyCFunction ) M_Mathutils_TranslationMatrix,
METH_VARARGS,
M_Mathutils_TranslationMatrix_doc},
{"CopyMat", ( PyCFunction ) M_Mathutils_CopyMat, METH_VARARGS,
M_Mathutils_CopyMat_doc},
{"OrthoProjectionMatrix",
( PyCFunction ) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS,
M_Mathutils_OrthoProjectionMatrix_doc},
{"MatMultVec", ( PyCFunction ) M_Mathutils_MatMultVec, METH_VARARGS,
M_Mathutils_MatMultVec_doc},
{"Quaternion", ( PyCFunction ) M_Mathutils_Quaternion, METH_VARARGS,
M_Mathutils_Quaternion_doc},
{"CopyQuat", ( PyCFunction ) M_Mathutils_CopyQuat, METH_VARARGS,
M_Mathutils_CopyQuat_doc},
{"CrossQuats", ( PyCFunction ) M_Mathutils_CrossQuats, METH_VARARGS,
M_Mathutils_CrossQuats_doc},
{"DotQuats", ( PyCFunction ) M_Mathutils_DotQuats, METH_VARARGS,
M_Mathutils_DotQuats_doc},
{"DifferenceQuats", ( PyCFunction ) M_Mathutils_DifferenceQuats,
METH_VARARGS,
M_Mathutils_DifferenceQuats_doc},
{"Slerp", ( PyCFunction ) M_Mathutils_Slerp, METH_VARARGS,
M_Mathutils_Slerp_doc},
{"Euler", ( PyCFunction ) M_Mathutils_Euler, METH_VARARGS,
M_Mathutils_Euler_doc},
{"CopyEuler", ( PyCFunction ) M_Mathutils_CopyEuler, METH_VARARGS,
M_Mathutils_CopyEuler_doc},
{"RotateEuler", ( PyCFunction ) M_Mathutils_RotateEuler, METH_VARARGS,
M_Mathutils_RotateEuler_doc},
{NULL, NULL, 0, NULL}
};
//***************************************************************************
// Function: M_Mathutils_Rand
//***************************************************************************
static PyObject *M_Mathutils_Rand( PyObject * self, PyObject * args )
{
float high, low, range;
double rand;
high = 1.0;
low = 0.0;
if( !PyArg_ParseTuple( args, "|ff", &low, &high ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected optional float & float\n" ) );
if( ( high < low ) || ( high < 0 && low > 0 ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"high value should be larger than low value\n" ) );
//seed the generator
BLI_srand( ( unsigned int ) ( PIL_check_seconds_timer( ) *
0x7FFFFFFF ) );
//get the random number 0 - 1
rand = BLI_drand( );
//set it to range
range = high - low;
rand = rand * range;
rand = rand + low;
return PyFloat_FromDouble( ( double ) rand );
}
//***************************************************************************
// Function: M_Mathutils_Vector
// Python equivalent: Blender.Mathutils.Vector
// Supports 2D, 3D, and 4D vector objects both int and float values
// accepted. Mixed float and int values accepted. Ints are parsed to float
//***************************************************************************
static PyObject *M_Mathutils_Vector( PyObject * self, PyObject * args )
{
PyObject *listObject = NULL;
int size, i;
float vec[4];
size = PySequence_Length(args);
if ( size == 1 ) {
listObject = PySequence_GetItem(args, 0);
if ( PySequence_Check(listObject) ) {
size = PySequence_Length(listObject);
} else {
goto bad_args; // Single argument was not a sequence
}
} else if ( size == 0 ) {
return ( PyObject * ) newVectorObject( NULL, 3 );
} else {
Py_INCREF(args);
listObject = args;
}
if (size<2 || size>4) {
goto bad_args; // Invalid vector size
}
for (i=0; i<size; i++) {
PyObject *v, *f;
v=PySequence_GetItem(listObject, i);
if (v==NULL) {
Py_DECREF(listObject);
return NULL; // Failed to read sequence
}
f=PyNumber_Float(v);
if(f==NULL) {
Py_DECREF(v);
goto bad_args;
}
vec[i]=PyFloat_AS_DOUBLE(f);
Py_DECREF(f);
Py_DECREF(v);
}
Py_DECREF(listObject);
return ( PyObject * ) newVectorObject( vec, size );
bad_args:
Py_XDECREF(listObject);
PyErr_SetString( PyExc_TypeError, "2-4 floats expected (optionally in a sequence)");
return NULL;
}
//***************************************************************************
//Begin Vector Utils
static PyObject *M_Mathutils_CopyVec( PyObject * self, PyObject * args )
{
VectorObject *vector;
float *vec;
int x;
PyObject *retval;
if( !PyArg_ParseTuple( args, "O!", &vector_Type, &vector ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected vector type\n" ) );
vec = PyMem_Malloc( vector->size * sizeof( float ) );
for( x = 0; x < vector->size; x++ ) {
vec[x] = vector->vec[x];
}
retval = ( PyObject * ) newVectorObject( vec, vector->size );
PyMem_Free( vec );
return retval;
}
//finds perpendicular vector - only 3D is supported
static PyObject *M_Mathutils_CrossVecs( PyObject * self, PyObject * args )
{
PyObject *vecCross;
VectorObject *vec1;
VectorObject *vec2;
if( !PyArg_ParseTuple
( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError, "expected 2 vector types\n" ) );
if( vec1->size != 3 || vec2->size != 3 )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"only 3D vectors are supported\n" ) );
vecCross = newVectorObject( NULL, 3 );
Crossf( ( ( VectorObject * ) vecCross )->vec, vec1->vec, vec2->vec );
return vecCross;
}
static PyObject *M_Mathutils_DotVecs( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
float dot;
int x;
dot = 0;
if( !PyArg_ParseTuple
( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError, "expected vector types\n" ) );
if( vec1->size != vec2->size )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"vectors must be of the same size\n" ) );
for( x = 0; x < vec1->size; x++ ) {
dot += vec1->vec[x] * vec2->vec[x];
}
return PyFloat_FromDouble( ( double ) dot );
}
static PyObject *M_Mathutils_AngleBetweenVecs( PyObject * self,
PyObject * args )
{
// original vectors, makea copy of these
VectorObject *vec1;
VectorObject *vec2;
/* copy of the 2 input vectors, these can be normalized
without input vectors being normalized. bugfix
no need to use vector objects, just use floats
No Chance of 4D vectors getting in.
Use doubles, since floats will return nan when input vecs are large.*/
double vec1copy[3];
double vec2copy[3];
float norm;
double dot, angleRads;
int x;
dot = 0.0f;
if( !PyArg_ParseTuple
( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError, "expected 2 vector types\n" ) );
if( vec1->size != vec2->size )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"vectors must be of the same size\n" ) );
if( vec1->size > 3 || vec2->size > 3 )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"only 2D,3D vectors are supported\n" ) );
/* Check for 2 vectors being the same */
if (vec1->size == 3 &&
vec1->vec[0] == vec2->vec[0] &&
vec1->vec[1] == vec2->vec[1] &&
vec1->vec[2] == vec2->vec[2])
return PyFloat_FromDouble( dot ); /* 2 points are the same, return zero */
else if (vec1->size == 2 &&
vec1->vec[0] == vec2->vec[0] &&
vec1->vec[1] == vec2->vec[1])
return PyFloat_FromDouble( dot ); /* 2 points are the same, return zero */
//normalize vec1copy
norm = 0.0f;
for( x = 0; x < vec1->size; x++ ) {
vec1copy[x] = vec1->vec[x]; /* Assign new vector in the loop */
norm += vec1copy[x] * vec1copy[x];
}
norm = ( float ) sqrt( norm );
for( x = 0; x < vec1->size; x++ ) {
vec1copy[x] /= norm;
}
//normalize vec2copy
norm = 0.0f;
for( x = 0; x < vec2->size; x++ ) {
vec2copy[x] = vec2->vec[x]; /* Assign new vector in the loop */
norm += vec2copy[x] * vec2copy[x];
}
norm = ( float ) sqrt( norm );
for( x = 0; x < vec2->size; x++ ) {
vec2copy[x] /= norm;
}
//dot product
for( x = 0; x < vec1->size; x++ ) {
dot += vec1copy[x] * vec2copy[x];
}
//I believe saacos checks to see if the vectors are normalized
angleRads = (double)acos( dot );
return PyFloat_FromDouble( angleRads * ( 180 / Py_PI ) );
}
static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
float *vec;
int x;
PyObject *retval;
if( !PyArg_ParseTuple
( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError, "expected vector types\n" ) );
if( vec1->size != vec2->size )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"vectors must be of the same size\n" ) );
vec = PyMem_Malloc( vec1->size * sizeof( float ) );
for( x = 0; x < vec1->size; x++ ) {
vec[x] = 0.5f * ( vec1->vec[x] + vec2->vec[x] );
}
retval = ( PyObject * ) newVectorObject( vec, vec1->size );
PyMem_Free( vec );
return retval;
}
//row vector multiplication
static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args )
{
PyObject *ob1 = NULL;
PyObject *ob2 = NULL;
MatrixObject *mat;
VectorObject *vec;
PyObject *retval;
float *vecNew;
int x, y;
int z = 0;
float dot = 0.0f;
//get pyObjects
if( !PyArg_ParseTuple
( args, "O!O!", &vector_Type, &ob1, &matrix_Type, &ob2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"vector and matrix object expected - in that order\n" ) );
mat = ( MatrixObject * ) ob2;
vec = ( VectorObject * ) ob1;
if( mat->colSize != vec->size )
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
"matrix col size and vector size must be the same\n" ) );
vecNew = PyMem_Malloc( vec->size * sizeof( float ) );
for( x = 0; x < mat->colSize; x++ ) {
for( y = 0; y < mat->rowSize; y++ ) {
dot += mat->matrix[y][x] * vec->vec[y];
}
vecNew[z] = dot;
z++;
dot = 0;
}
retval = ( PyObject * ) newVectorObject( vecNew, vec->size );
PyMem_Free( vecNew );
return retval;
}
static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
PyObject *retval;
float *vec;
float dot = 0.0f;
float dot2 = 0.0f;
int x;
if( !PyArg_ParseTuple
( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError, "expected vector types\n" ) );
if( vec1->size != vec2->size )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"vectors must be of the same size\n" ) );
vec = PyMem_Malloc( vec1->size * sizeof( float ) );
//dot of vec1 & vec2
for( x = 0; x < vec1->size; x++ ) {
dot += vec1->vec[x] * vec2->vec[x];
}
//dot of vec2 & vec2
for( x = 0; x < vec2->size; x++ ) {
dot2 += vec2->vec[x] * vec2->vec[x];
}
dot /= dot2;
for( x = 0; x < vec1->size; x++ ) {
vec[x] = dot * vec2->vec[x];
}
retval = ( PyObject * ) newVectorObject( vec, vec1->size );
PyMem_Free( vec );
return retval;
}
//End Vector Utils
//***************************************************************************
// Function: M_Mathutils_Matrix // Python equivalent: Blender.Mathutils.Matrix
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_Matrix( PyObject * self, PyObject * args )
{
PyObject *rowA = NULL;
PyObject *rowB = NULL;
PyObject *rowC = NULL;
PyObject *rowD = NULL;
PyObject *checkOb = NULL;
PyObject *retval = NULL;
int x, rowSize, colSize;
float *mat;
int OK;
if( !PyArg_ParseTuple( args, "|O!O!O!O!", &PyList_Type, &rowA,
&PyList_Type, &rowB,
&PyList_Type, &rowC, &PyList_Type, &rowD ) ) {
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected 0, 2,3 or 4 lists\n" ) );
}
if( !rowA )
return newMatrixObject( NULL, 4, 4 );
if( !rowB )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected 0, 2,3 or 4 lists\n" ) );
//get rowSize
if( rowC ) {
if( rowD ) {
rowSize = 4;
} else {
rowSize = 3;
}
} else {
rowSize = 2;
}
//check size and get colSize
OK = 0;
if( ( PyList_Size( rowA ) == PyList_Size( rowB ) ) ) {
if( rowC ) {
if( ( PyList_Size( rowA ) == PyList_Size( rowC ) ) ) {
if( rowD ) {
if( ( PyList_Size( rowA ) ==
PyList_Size( rowD ) ) ) {
OK = 1;
}
}
OK = 1;
}
} else
OK = 1;
}
if( !OK )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"each row of vector must contain the same number of parameters\n" );
colSize = PyList_Size( rowA );
//check for numeric types
/* PyList_GetItem() returns borrowed ref */
for( x = 0; x < colSize; x++ ) {
checkOb = PyList_GetItem( rowA, x );
if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"1st list - expected list of numbers\n" ) );
checkOb = PyList_GetItem( rowB, x );
if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"2nd list - expected list of numbers\n" ) );
if( rowC ) {
checkOb = PyList_GetItem( rowC, x );
if( !PyInt_Check( checkOb )
&& !PyFloat_Check( checkOb ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"3rd list - expected list of numbers\n" ) );
}
if( rowD ) {
checkOb = PyList_GetItem( rowD, x );
if( !PyInt_Check( checkOb )
&& !PyFloat_Check( checkOb ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"4th list - expected list of numbers\n" ) );
}
}
//allocate space for 1D array
mat = PyMem_Malloc( rowSize * colSize * sizeof( float ) );
//parse rows
for( x = 0; x < colSize; x++ ) {
if( !PyArg_Parse( PyList_GetItem( rowA, x ), "f", &mat[x] ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"rowA - python list not parseable\n" );
}
for( x = 0; x < colSize; x++ ) {
if( !PyArg_Parse
( PyList_GetItem( rowB, x ), "f", &mat[( colSize + x )] ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"rowB - python list not parseable\n" );
}
if( rowC ) {
for( x = 0; x < colSize; x++ ) {
if( !PyArg_Parse
( PyList_GetItem( rowC, x ), "f",
&mat[( ( 2 * colSize ) + x )] ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"rowC - python list not parseable\n" );
}
}
if( rowD ) {
for( x = 0; x < colSize; x++ ) {
if( !PyArg_Parse
( PyList_GetItem( rowD, x ), "f",
&mat[( ( 3 * colSize ) + x )] ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"rowD - python list not parseable\n" );
}
}
//pass to matrix creation
retval = newMatrixObject( mat, rowSize, colSize );
PyMem_Free( mat);
return retval;
}
//***************************************************************************
// Function: M_Mathutils_RotationMatrix
// Python equivalent: Blender.Mathutils.RotationMatrix
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_RotationMatrix( PyObject * self, PyObject * args )
{
PyObject *retval;
float *mat;
float angle = 0.0f;
-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.
2005-05-20 19:28:04 +00:00
char *axis = NULL;
VectorObject *vec = NULL;
int matSize;
float norm = 0.0f;
float cosAngle = 0.0f;
float sinAngle = 0.0f;
if( !PyArg_ParseTuple
( args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec ) ) {
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"expected float int and optional string and vector\n" ) );
}
if( angle < -360.0f || angle > 360.0f )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"angle size not appropriate\n" );
if( matSize != 2 && matSize != 3 && matSize != 4 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"can only return a 2x2 3x3 or 4x4 matrix\n" );
if( matSize == 2 && ( axis != NULL || vec != NULL ) )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"cannot create a 2x2 rotation matrix around arbitrary axis\n" );
if( ( matSize == 3 || matSize == 4 ) && axis == NULL )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"please choose an axis of rotation\n" );
if( axis ) {
if( ( ( strcmp( axis, "r" ) == 0 ) ||
( strcmp( axis, "R" ) == 0 ) ) && vec == NULL )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"please define the arbitrary axis of rotation\n" );
}
if( vec ) {
if( vec->size != 3 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"the arbitrary axis must be a 3D vector\n" );
}
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
//convert to radians
angle = angle * ( float ) ( Py_PI / 180 );
if( axis == NULL && matSize == 2 ) {
//2D rotation matrix
mat[0] = ( ( float ) cos( ( double ) ( angle ) ) );
mat[1] = ( ( float ) sin( ( double ) ( angle ) ) );
mat[2] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
mat[3] = ( ( float ) cos( ( double ) ( angle ) ) );
} else if( ( strcmp( axis, "x" ) == 0 ) ||
( strcmp( axis, "X" ) == 0 ) ) {
//rotation around X
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = ( ( float ) cos( ( double ) ( angle ) ) );
mat[5] = ( ( float ) sin( ( double ) ( angle ) ) );
mat[6] = 0.0f;
mat[7] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
mat[8] = ( ( float ) cos( ( double ) ( angle ) ) );
} else if( ( strcmp( axis, "y" ) == 0 ) ||
( strcmp( axis, "Y" ) == 0 ) ) {
//rotation around Y
mat[0] = ( ( float ) cos( ( double ) ( angle ) ) );
mat[1] = 0.0f;
mat[2] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
mat[3] = 0.0f;
mat[4] = 1.0f;
mat[5] = 0.0f;
mat[6] = ( ( float ) sin( ( double ) ( angle ) ) );
mat[7] = 0.0f;
mat[8] = ( ( float ) cos( ( double ) ( angle ) ) );
} else if( ( strcmp( axis, "z" ) == 0 ) ||
( strcmp( axis, "Z" ) == 0 ) ) {
//rotation around Z
mat[0] = ( ( float ) cos( ( double ) ( angle ) ) );
mat[1] = ( ( float ) sin( ( double ) ( angle ) ) );
mat[2] = 0.0f;
mat[3] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
mat[4] = ( ( float ) cos( ( double ) ( angle ) ) );
mat[5] = 0.0f;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 1.0f;
} else if( ( strcmp( axis, "r" ) == 0 ) ||
( strcmp( axis, "R" ) == 0 ) ) {
//arbitrary rotation
//normalize arbitrary axis
norm = ( float ) sqrt( vec->vec[0] * vec->vec[0] +
vec->vec[1] * vec->vec[1] +
vec->vec[2] * vec->vec[2] );
vec->vec[0] /= norm;
vec->vec[1] /= norm;
vec->vec[2] /= norm;
//create matrix
cosAngle = ( ( float ) cos( ( double ) ( angle ) ) );
sinAngle = ( ( float ) sin( ( double ) ( angle ) ) );
mat[0] = ( ( vec->vec[0] * vec->vec[0] ) * ( 1 - cosAngle ) ) +
cosAngle;
mat[1] = ( ( vec->vec[0] * vec->vec[1] ) * ( 1 - cosAngle ) ) +
( vec->vec[2] * sinAngle );
mat[2] = ( ( vec->vec[0] * vec->vec[2] ) * ( 1 - cosAngle ) ) -
( vec->vec[1] * sinAngle );
mat[3] = ( ( vec->vec[0] * vec->vec[1] ) * ( 1 - cosAngle ) ) -
( vec->vec[2] * sinAngle );
mat[4] = ( ( vec->vec[1] * vec->vec[1] ) * ( 1 - cosAngle ) ) +
cosAngle;
mat[5] = ( ( vec->vec[1] * vec->vec[2] ) * ( 1 - cosAngle ) ) +
( vec->vec[0] * sinAngle );
mat[6] = ( ( vec->vec[0] * vec->vec[2] ) * ( 1 - cosAngle ) ) +
( vec->vec[1] * sinAngle );
mat[7] = ( ( vec->vec[1] * vec->vec[2] ) * ( 1 - cosAngle ) ) -
( vec->vec[0] * sinAngle );
mat[8] = ( ( vec->vec[2] * vec->vec[2] ) * ( 1 - cosAngle ) ) +
cosAngle;
} else {
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"unrecognizable axis of rotation type - expected x,y,z or r\n" );
}
if( matSize == 4 ) {
//resize matrix
mat[15] = 1.0f;
mat[14] = 0.0f;
mat[13] = 0.0f;
mat[12] = 0.0f;
mat[11] = 0.0f;
mat[10] = mat[8];
mat[9] = mat[7];
mat[8] = mat[6];
mat[7] = 0.0f;
mat[6] = mat[5];
mat[5] = mat[4];
mat[4] = mat[3];
mat[3] = 0.0f;
}
//pass to matrix creation
retval = newMatrixObject( mat, matSize, matSize );
PyMem_Free( mat );
return retval;
}
//***************************************************************************
// Function: M_Mathutils_TranslationMatrix
// Python equivalent: Blender.Mathutils.TranslationMatrix
//***************************************************************************
static PyObject *M_Mathutils_TranslationMatrix( PyObject * self,
PyObject * args )
{
VectorObject *vec;
PyObject *retval;
float *mat;
if( !PyArg_ParseTuple( args, "O!", &vector_Type, &vec ) ) {
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected vector\n" ) );
}
if( vec->size != 3 && vec->size != 4 ) {
return EXPP_ReturnPyObjError( PyExc_TypeError,
"vector must be 3D or 4D\n" );
}
mat = PyMem_Malloc( 4 * 4 * sizeof( float ) );
Mat4One( ( float ( * )[4] ) mat );
mat[12] = vec->vec[0];
mat[13] = vec->vec[1];
mat[14] = vec->vec[2];
retval = newMatrixObject( mat, 4, 4 );
PyMem_Free( mat );
return retval;
}
//***************************************************************************
// Function: M_Mathutils_ScaleMatrix
// Python equivalent: Blender.Mathutils.ScaleMatrix
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_ScaleMatrix( PyObject * self, PyObject * args )
{
float factor;
int matSize;
VectorObject *vec = NULL;
float *mat;
float norm = 0.0f;
int x;
PyObject *retval;
if( !PyArg_ParseTuple
( args, "fi|O!", &factor, &matSize, &vector_Type, &vec ) ) {
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"expected float int and optional vector\n" ) );
}
if( matSize != 2 && matSize != 3 && matSize != 4 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"can only return a 2x2 3x3 or 4x4 matrix\n" );
if( vec ) {
if( vec->size > 2 && matSize == 2 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"please use 2D vectors when scaling in 2D\n" );
}
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
if( vec == NULL ) { //scaling along axis
if( matSize == 2 ) {
mat[0] = factor;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = factor;
} else {
mat[0] = factor;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = factor;
mat[5] = 0.0f;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = factor;
}
} else { //scaling in arbitrary direction
//normalize arbitrary axis
for( x = 0; x < vec->size; x++ ) {
norm += vec->vec[x] * vec->vec[x];
}
norm = ( float ) sqrt( norm );
for( x = 0; x < vec->size; x++ ) {
vec->vec[x] /= norm;
}
if( matSize == 2 ) {
mat[0] = 1 +
( ( factor -
1 ) * ( vec->vec[0] * vec->vec[0] ) );
mat[1] = ( ( factor -
1 ) * ( vec->vec[0] * vec->vec[1] ) );
mat[2] = ( ( factor -
1 ) * ( vec->vec[0] * vec->vec[1] ) );
mat[3] = 1 +
( ( factor -
1 ) * ( vec->vec[1] * vec->vec[1] ) );
} else {
mat[0] = 1 +
( ( factor -
1 ) * ( vec->vec[0] * vec->vec[0] ) );
mat[1] = ( ( factor -
1 ) * ( vec->vec[0] * vec->vec[1] ) );
mat[2] = ( ( factor -
1 ) * ( vec->vec[0] * vec->vec[2] ) );
mat[3] = ( ( factor -
1 ) * ( vec->vec[0] * vec->vec[1] ) );
mat[4] = 1 +
( ( factor -
1 ) * ( vec->vec[1] * vec->vec[1] ) );
mat[5] = ( ( factor -
1 ) * ( vec->vec[1] * vec->vec[2] ) );
mat[6] = ( ( factor -
1 ) * ( vec->vec[0] * vec->vec[2] ) );
mat[7] = ( ( factor -
1 ) * ( vec->vec[1] * vec->vec[2] ) );
mat[8] = 1 +
( ( factor -
1 ) * ( vec->vec[2] * vec->vec[2] ) );
}
}
if( matSize == 4 ) {
//resize matrix
mat[15] = 1.0f;
mat[14] = 0.0f;
mat[13] = 0.0f;
mat[12] = 0.0f;
mat[11] = 0.0f;
mat[10] = mat[8];
mat[9] = mat[7];
mat[8] = mat[6];
mat[7] = 0.0f;
mat[6] = mat[5];
mat[5] = mat[4];
mat[4] = mat[3];
mat[3] = 0.0f;
}
//pass to matrix creation
retval = newMatrixObject( mat, matSize, matSize );
PyMem_Free( mat );
return retval;
}
//***************************************************************************
// Function: M_Mathutils_OrthoProjectionMatrix
// Python equivalent: Blender.Mathutils.OrthoProjectionMatrix
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_OrthoProjectionMatrix( PyObject * self,
PyObject * args )
{
-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.
2005-05-20 19:28:04 +00:00
char *plane;
int matSize;
float *mat;
VectorObject *vec = NULL;
float norm = 0.0f;
int x;
PyObject *retval;
if( !PyArg_ParseTuple
( args, "si|O!", &plane, &matSize, &vector_Type, &vec ) ) {
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"expected string and int and optional vector\n" ) );
}
if( matSize != 2 && matSize != 3 && matSize != 4 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"can only return a 2x2 3x3 or 4x4 matrix\n" );
if( vec ) {
if( vec->size > 2 && matSize == 2 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"please use 2D vectors when scaling in 2D\n" );
}
if( vec == NULL ) { //ortho projection onto cardinal plane
if( ( ( strcmp( plane, "x" ) == 0 )
|| ( strcmp( plane, "X" ) == 0 ) ) && matSize == 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
} else if( ( ( strcmp( plane, "y" ) == 0 )
|| ( strcmp( plane, "Y" ) == 0 ) )
&& matSize == 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 0.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 1.0f;
} else if( ( ( strcmp( plane, "xy" ) == 0 )
|| ( strcmp( plane, "XY" ) == 0 ) )
&& matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = 1.0f;
mat[5] = 0.0f;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 0.0f;
} else if( ( ( strcmp( plane, "xz" ) == 0 )
|| ( strcmp( plane, "XZ" ) == 0 ) )
&& matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = 0.0f;
mat[5] = 0.0f;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 1.0f;
} else if( ( ( strcmp( plane, "yz" ) == 0 )
|| ( strcmp( plane, "YZ" ) == 0 ) )
&& matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 0.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = 1.0f;
mat[5] = 0.0f;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 1.0f;
} else {
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"unknown plane - expected: x, y, xy, xz, yz\n" );
}
} else { //arbitrary plane
//normalize arbitrary axis
for( x = 0; x < vec->size; x++ ) {
norm += vec->vec[x] * vec->vec[x];
}
norm = ( float ) sqrt( norm );
for( x = 0; x < vec->size; x++ ) {
vec->vec[x] /= norm;
}
if( ( ( strcmp( plane, "r" ) == 0 )
|| ( strcmp( plane, "R" ) == 0 ) ) && matSize == 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 1 - ( vec->vec[0] * vec->vec[0] );
mat[1] = -( vec->vec[0] * vec->vec[1] );
mat[2] = -( vec->vec[0] * vec->vec[1] );
mat[3] = 1 - ( vec->vec[1] * vec->vec[1] );
} else if( ( ( strcmp( plane, "r" ) == 0 )
|| ( strcmp( plane, "R" ) == 0 ) )
&& matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize *
sizeof( float ) );
mat[0] = 1 - ( vec->vec[0] * vec->vec[0] );
mat[1] = -( vec->vec[0] * vec->vec[1] );
mat[2] = -( vec->vec[0] * vec->vec[2] );
mat[3] = -( vec->vec[0] * vec->vec[1] );
mat[4] = 1 - ( vec->vec[1] * vec->vec[1] );
mat[5] = -( vec->vec[1] * vec->vec[2] );
mat[6] = -( vec->vec[0] * vec->vec[2] );
mat[7] = -( vec->vec[1] * vec->vec[2] );
mat[8] = 1 - ( vec->vec[2] * vec->vec[2] );
} else {
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"unknown plane - expected: 'r' expected for axis designation\n" );
}
}
if( matSize == 4 ) {
//resize matrix
mat[15] = 1.0f;
mat[14] = 0.0f;
mat[13] = 0.0f;
mat[12] = 0.0f;
mat[11] = 0.0f;
mat[10] = mat[8];
mat[9] = mat[7];
mat[8] = mat[6];
mat[7] = 0.0f;
mat[6] = mat[5];
mat[5] = mat[4];
mat[4] = mat[3];
mat[3] = 0.0f;
}
//pass to matrix creation
retval = newMatrixObject( mat, matSize, matSize );
PyMem_Free( mat );
return retval;
}
//***************************************************************************
// Function: M_Mathutils_ShearMatrix
// Python equivalent: Blender.Mathutils.ShearMatrix
//***************************************************************************
static PyObject *M_Mathutils_ShearMatrix( PyObject * self, PyObject * args )
{
float factor;
int matSize;
char *plane;
float *mat;
PyObject *retval;
if( !PyArg_ParseTuple( args, "sfi", &plane, &factor, &matSize ) ) {
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected string float and int\n" ) );
}
if( matSize != 2 && matSize != 3 && matSize != 4 )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"can only return a 2x2 3x3 or 4x4 matrix\n" );
if( ( ( strcmp( plane, "x" ) == 0 ) || ( strcmp( plane, "X" ) == 0 ) )
&& matSize == 2 ) {
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = factor;
mat[3] = 1.0f;
} else if( ( ( strcmp( plane, "y" ) == 0 )
|| ( strcmp( plane, "Y" ) == 0 ) ) && matSize == 2 ) {
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
mat[0] = 1.0f;
mat[1] = factor;
mat[2] = 0.0f;
mat[3] = 1.0f;
} else if( ( ( strcmp( plane, "xy" ) == 0 )
|| ( strcmp( plane, "XY" ) == 0 ) ) && matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = 1.0f;
mat[5] = 0.0f;
mat[6] = factor;
mat[7] = factor;
mat[8] = 0.0f;
} else if( ( ( strcmp( plane, "xz" ) == 0 )
|| ( strcmp( plane, "XZ" ) == 0 ) ) && matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
mat[0] = 1.0f;
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = factor;
mat[4] = 1.0f;
mat[5] = factor;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 1.0f;
} else if( ( ( strcmp( plane, "yz" ) == 0 )
|| ( strcmp( plane, "YZ" ) == 0 ) ) && matSize > 2 ) {
mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
mat[0] = 1.0f;
mat[1] = factor;
mat[2] = factor;
mat[3] = 0.0f;
mat[4] = 1.0f;
mat[5] = 0.0f;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 1.0f;
} else {
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n" );
}
if( matSize == 4 ) {
//resize matrix
mat[15] = 1.0f;
mat[14] = 0.0f;
mat[13] = 0.0f;
mat[12] = 0.0f;
mat[11] = 0.0f;
mat[10] = mat[8];
mat[9] = mat[7];
mat[8] = mat[6];
mat[7] = 0.0f;
mat[6] = mat[5];
mat[5] = mat[4];
mat[4] = mat[3];
mat[3] = 0.0f;
}
//pass to matrix creation
retval = newMatrixObject( mat, matSize, matSize );
PyMem_Free( mat );
return retval;
}
//***************************************************************************
//Begin Matrix Utils
static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args )
{
MatrixObject *matrix;
float *mat;
int x, y, z;
PyObject *retval;
if( !PyArg_ParseTuple( args, "O!", &matrix_Type, &matrix ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected matrix\n" ) );
mat = PyMem_Malloc( matrix->rowSize * matrix->colSize *
sizeof( float ) );
z = 0;
for( x = 0; x < matrix->rowSize; x++ ) {
for( y = 0; y < matrix->colSize; y++ ) {
mat[z] = matrix->matrix[x][y];
z++;
}
}
retval = ( PyObject * ) newMatrixObject( mat, matrix->rowSize,
matrix->colSize );
PyMem_Free( mat );
return retval;
}
static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args )
{
PyObject *ob1 = NULL;
PyObject *ob2 = NULL;
MatrixObject *mat;
VectorObject *vec;
PyObject *retval;
float *vecNew;
int x, y;
int z = 0;
float dot = 0.0f;
//get pyObjects
if( !PyArg_ParseTuple
( args, "O!O!", &matrix_Type, &ob1, &vector_Type, &ob2 ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"matrix and vector object expected - in that order\n" ) );
mat = ( MatrixObject * ) ob1;
vec = ( VectorObject * ) ob2;
if( mat->rowSize != vec->size )
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
"matrix row size and vector size must be the same\n" ) );
vecNew = PyMem_Malloc( vec->size * sizeof( float ) );
for( x = 0; x < mat->rowSize; x++ ) {
for( y = 0; y < mat->colSize; y++ ) {
dot += mat->matrix[x][y] * vec->vec[y];
-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.
2005-05-20 19:28:04 +00:00
}
vecNew[z] = dot;
z++;
dot = 0;
}
retval = ( PyObject * ) newVectorObject( vecNew, vec->size );
PyMem_Free( vecNew );
return retval;
}
//***************************************************************************
// Function: M_Mathutils_Quaternion
// Python equivalent: Blender.Mathutils.Quaternion
//***************************************************************************
static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args )
{
PyObject *listObject;
float *vec = NULL;
float *quat = NULL;
float angle = 0.0f;
int x;
float norm;
PyObject *retval;
if( !PyArg_ParseTuple
( args, "O!|f", &PyList_Type, &listObject, &angle ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"expected list and optional float\n" ) );
if( PyList_Size( listObject ) != 4 && PyList_Size( listObject ) != 3 )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"3 or 4 expected floats for the quaternion\n" ) );
vec = PyMem_Malloc( PyList_Size( listObject ) * sizeof( float ) );
for( x = 0; x < PyList_Size( listObject ); x++ ) {
if( !PyArg_Parse
( PyList_GetItem( listObject, x ), "f", &vec[x] ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"python list not parseable\n" );
-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.
2005-05-20 19:28:04 +00:00
}
if( PyList_Size( listObject ) == 3 ) { //an axis of rotation
norm = ( float ) sqrt( vec[0] * vec[0] + vec[1] * vec[1] +
vec[2] * vec[2] );
vec[0] /= norm;
vec[1] /= norm;
vec[2] /= norm;
angle = angle * ( float ) ( Py_PI / 180 );
quat = PyMem_Malloc( 4 * sizeof( float ) );
quat[0] = ( float ) ( cos( ( double ) ( angle ) / 2 ) );
quat[1] =
( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[0];
quat[2] =
( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[1];
quat[3] =
( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[2];
retval = newQuaternionObject( quat );
} else
retval = newQuaternionObject( vec );
/* freeing a NULL ptr is ok */
PyMem_Free( vec );
PyMem_Free( quat );
return retval;
}
//***************************************************************************
//Begin Quaternion Utils
static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
float *quat = NULL;
PyObject *retval;
if( !PyArg_ParseTuple( args, "O!", &quaternion_Type, &quatU ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected Quaternion type" ) );
quat = PyMem_Malloc( 4 * sizeof( float ) );
quat[0] = quatU->quat[0];
quat[1] = quatU->quat[1];
quat[2] = quatU->quat[2];
quat[3] = quatU->quat[3];
retval = ( PyObject * ) newQuaternionObject( quat );
PyMem_Free( quat );
return retval;
}
static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
float *quat = NULL;
PyObject *retval;
if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, &quatU,
&quaternion_Type, &quatV ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected Quaternion types" ) );
quat = PyMem_Malloc( 4 * sizeof( float ) );
QuatMul( quat, quatU->quat, quatV->quat );
retval = ( PyObject * ) newQuaternionObject( quat );
PyMem_Free( quat );
return retval;
}
static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
int x;
float dot = 0.0f;
if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, &quatU,
&quaternion_Type, &quatV ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected Quaternion types" ) );
for( x = 0; x < 4; x++ ) {
dot += quatU->quat[x] * quatV->quat[x];
}
return PyFloat_FromDouble( ( double ) ( dot ) );
}
static PyObject *M_Mathutils_DifferenceQuats( PyObject * self,
PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
float *quat = NULL;
float *tempQuat = NULL;
PyObject *retval;
int x;
float dot = 0.0f;
if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type,
&quatU, &quaternion_Type, &quatV ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected Quaternion types" ) );
quat = PyMem_Malloc( 4 * sizeof( float ) );
tempQuat = PyMem_Malloc( 4 * sizeof( float ) );
tempQuat[0] = quatU->quat[0];
tempQuat[1] = -quatU->quat[1];
tempQuat[2] = -quatU->quat[2];
tempQuat[3] = -quatU->quat[3];
dot = ( float ) sqrt( ( double ) tempQuat[0] * ( double ) tempQuat[0] +
( double ) tempQuat[1] * ( double ) tempQuat[1] +
( double ) tempQuat[2] * ( double ) tempQuat[2] +
( double ) tempQuat[3] *
( double ) tempQuat[3] );
for( x = 0; x < 4; x++ ) {
tempQuat[x] /= ( dot * dot );
}
QuatMul( quat, tempQuat, quatV->quat );
retval = ( PyObject * ) newQuaternionObject( quat );
PyMem_Free( quat );
PyMem_Free( tempQuat );
return retval;
}
static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
float *quat = NULL;
PyObject *retval;
float param, x, y, cosD, sinD, deltaD, IsinD, val;
int flag, z;
if( !PyArg_ParseTuple( args, "O!O!f", &quaternion_Type,
&quatU, &quaternion_Type, &quatV, &param ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected Quaternion types and float" ) );
quat = PyMem_Malloc( 4 * sizeof( float ) );
cosD = quatU->quat[0] * quatV->quat[0] +
quatU->quat[1] * quatV->quat[1] +
quatU->quat[2] * quatV->quat[2] +
quatU->quat[3] * quatV->quat[3];
flag = 0;
if( cosD < 0.0f ) {
flag = 1;
cosD = -cosD;
}
if( cosD > .99999f ) {
x = 1.0f - param;
y = param;
} else {
sinD = ( float ) sqrt( 1.0f - cosD * cosD );
deltaD = ( float ) atan2( sinD, cosD );
IsinD = 1.0f / sinD;
x = ( float ) sin( ( 1.0f - param ) * deltaD ) * IsinD;
y = ( float ) sin( param * deltaD ) * IsinD;
}
for( z = 0; z < 4; z++ ) {
val = quatV->quat[z];
if( val )
val = -val;
quat[z] = ( quatU->quat[z] * x ) + ( val * y );
}
retval = ( PyObject * ) newQuaternionObject( quat );
PyMem_Free( quat );
return retval;
-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.
2005-05-20 19:28:04 +00:00
}
//***************************************************************************
// Function: M_Mathutils_Euler
// Python equivalent: Blender.Mathutils.Euler
//***************************************************************************
static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args )
{
PyObject *listObject;
float *vec = NULL;
PyObject *retval;
int x;
if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &listObject ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected list\n" ) );
if( PyList_Size( listObject ) != 3 )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"only 3d eulers are supported\n" );
vec = PyMem_Malloc( 3 * sizeof( float ) );
for( x = 0; x < 3; x++ ) {
if( !PyArg_Parse
( PyList_GetItem( listObject, x ), "f", &vec[x] ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"python list not parseable\n" );
-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.
2005-05-20 19:28:04 +00:00
}
retval = ( PyObject * ) newEulerObject( vec );
PyMem_Free( vec );
return retval;
-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.
2005-05-20 19:28:04 +00:00
}
//***************************************************************************
//Begin Euler Util
static PyObject *M_Mathutils_CopyEuler( PyObject * self, PyObject * args )
-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.
2005-05-20 19:28:04 +00:00
{
EulerObject *eulU;
float *eul = NULL;
PyObject *retval;
if( !PyArg_ParseTuple( args, "O!", &euler_Type, &eulU ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected Euler types" ) );
eul = PyMem_Malloc( 3 * sizeof( float ) );
eul[0] = eulU->eul[0];
eul[1] = eulU->eul[1];
eul[2] = eulU->eul[2];
retval = ( PyObject * ) newEulerObject( eul );
PyMem_Free( eul );
return retval;
-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.
2005-05-20 19:28:04 +00:00
}
static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args )
-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.
2005-05-20 19:28:04 +00:00
{
EulerObject *Eul;
float angle;
char *axis;
int x;
if( !PyArg_ParseTuple
( args, "O!fs", &euler_Type, &Eul, &angle, &axis ) )
return ( EXPP_ReturnPyObjError
( PyExc_TypeError,
"expected euler type & float & string" ) );
-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.
2005-05-20 19:28:04 +00:00
angle *= ( float ) ( Py_PI / 180 );
for( x = 0; x < 3; x++ ) {
Eul->eul[x] *= ( float ) ( Py_PI / 180 );
}
euler_rot( Eul->eul, angle, *axis );
for( x = 0; x < 3; x++ ) {
Eul->eul[x] *= ( float ) ( 180 / Py_PI );
}
return EXPP_incr_ret( Py_None );
}
-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.
2005-05-20 19:28:04 +00:00
//***************************************************************************
// Function: Mathutils_Init
//***************************************************************************
PyObject *Mathutils_Init( void )
{
PyObject *mod =
Py_InitModule3( "Blender.Mathutils", M_Mathutils_methods,
M_Mathutils_doc );
return ( mod );
}