This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/python/api2_2x/Mathutils.c
Stephen Swaney a509b8adc9 Another round in the Great BPy Cleanup:
Run everything thru indent to cleanup spaces vs tabs.
Clean up some of the comments by hand.
BGL.c was not touched due to all that macro wackyness.

There are no functional changes to the code.
Pre-indent versions of source are tagged with
tag bpy-cleanup-20040925 , just in case.
2004-09-25 20:30:40 +00:00

1347 lines
38 KiB
C

/*
* $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
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include "Mathutils.h"
//***************************************************************************
// 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;
PyObject *checkOb = NULL;
int x;
float *vec;
if( !PyArg_ParseTuple( args, "|O!", &PyList_Type, &listObject ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"0 or 1 list expected" ) );
if( !listObject )
return ( PyObject * ) newVectorObject( NULL, 3 );
//2D 3D 4D supported
if( PyList_Size( listObject ) != 2 && PyList_Size( listObject ) != 3
&& PyList_Size( listObject ) != 4 )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"2D, 3D and 4D vectors supported\n" ) );
for( x = 0; x < PyList_Size( listObject ); x++ ) {
checkOb = PyList_GetItem( listObject, x );
if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected list of numbers\n" ) );
}
//allocate memory
vec = PyMem_Malloc( PyList_Size( listObject ) * sizeof( float ) );
//parse it all as floats
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" );
}
}
return ( PyObject * ) newVectorObject( vec,
PyList_Size( listObject ) );
}
//***************************************************************************
//Begin Vector Utils
static PyObject *M_Mathutils_CopyVec( PyObject * self, PyObject * args )
{
VectorObject *vector;
float *vec;
int x;
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];
}
return ( PyObject * ) newVectorObject( vec, vector->size );
}
//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( PyMem_Malloc( 3 * sizeof( float ) ), 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 )
{
VectorObject *vec1;
VectorObject *vec2;
float dot, angleRads, norm;
int x;
dot = 0;
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" ) );
//normalize vec1
norm = 0.0f;
for( x = 0; x < vec1->size; x++ ) {
norm += vec1->vec[x] * vec1->vec[x];
}
norm = ( float ) sqrt( norm );
for( x = 0; x < vec1->size; x++ ) {
vec1->vec[x] /= norm;
}
//normalize vec2
norm = 0.0f;
for( x = 0; x < vec2->size; x++ ) {
norm += vec2->vec[x] * vec2->vec[x];
}
norm = ( float ) sqrt( norm );
for( x = 0; x < vec2->size; x++ ) {
vec2->vec[x] /= norm;
}
//dot product
for( x = 0; x < vec1->size; x++ ) {
dot += vec1->vec[x] * vec2->vec[x];
}
//I believe saacos checks to see if the vectors are normalized
angleRads = saacos( dot );
return PyFloat_FromDouble( ( double )
( angleRads * ( 180 / Py_PI ) ) );
}
static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
float *vec;
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 ) );
for( x = 0; x < vec1->size; x++ ) {
vec[x] = 0.5f * ( vec1->vec[x] + vec2->vec[x] );
}
return ( PyObject * ) newVectorObject( vec, vec1->size );
}
//row vector multiplication
static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args )
{
PyObject *ob1 = NULL;
PyObject *ob2 = NULL;
MatrixObject *mat;
VectorObject *vec;
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;
}
return ( PyObject * ) newVectorObject( vecNew, vec->size );
}
static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args )
{
VectorObject *vec1;
VectorObject *vec2;
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];
}
return ( PyObject * ) newVectorObject( vec, vec1->size );
}
//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;
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
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
return newMatrixObject( mat, rowSize, colSize );
}
//***************************************************************************
// 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 )
{
float *mat;
float angle = 0.0f;
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
return newMatrixObject( mat, matSize, matSize );
}
//***************************************************************************
// Function: M_Mathutils_TranslationMatrix
// Python equivalent: Blender.Mathutils.TranslationMatrix
//***************************************************************************
static PyObject *M_Mathutils_TranslationMatrix( PyObject * self,
PyObject * args )
{
VectorObject *vec;
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];
return newMatrixObject( mat, 4, 4 );
}
//***************************************************************************
// 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;
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
return newMatrixObject( mat, matSize, matSize );
}
//***************************************************************************
// 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 )
{
char *plane;
int matSize;
float *mat;
VectorObject *vec = NULL;
float norm = 0.0f;
int x;
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
return newMatrixObject( mat, matSize, matSize );
}
//***************************************************************************
// 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;
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
return newMatrixObject( mat, matSize, matSize );
}
//***************************************************************************
//Begin Matrix Utils
static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args )
{
MatrixObject *matrix;
float *mat;
int x, y, z;
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++;
}
}
return ( PyObject * ) newMatrixObject( mat, matrix->rowSize,
matrix->colSize );
}
static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args )
{
PyObject *ob1 = NULL;
PyObject *ob2 = NULL;
MatrixObject *mat;
VectorObject *vec;
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];
}
vecNew[z] = dot;
z++;
dot = 0;
}
return ( PyObject * ) newVectorObject( vecNew, vec->size );
}
//***************************************************************************
// Function: M_Mathutils_Quaternion
// Python equivalent: Blender.Mathutils.Quaternion
//***************************************************************************
static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args )
{
PyObject *listObject;
float *vec;
float *quat;
float angle = 0.0f;
int x;
float norm;
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" );
}
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];
PyMem_Free( vec );
return newQuaternionObject( quat );
} else
return newQuaternionObject( vec );
}
//***************************************************************************
//Begin Quaternion Utils
static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
float *quat;
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];
return ( PyObject * ) newQuaternionObject( quat );
}
static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
float *quat;
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 );
return ( PyObject * ) newQuaternionObject( quat );
}
static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
float *quat;
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 ) );
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;
float *tempQuat;
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 );
return ( PyObject * ) newQuaternionObject( quat );
}
static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args )
{
QuaternionObject *quatU;
QuaternionObject *quatV;
float *quat;
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 );
}
return ( PyObject * ) newQuaternionObject( quat );
}
//***************************************************************************
// Function: M_Mathutils_Euler
// Python equivalent: Blender.Mathutils.Euler
//***************************************************************************
static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args )
{
PyObject *listObject;
float *vec;
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" );
}
return ( PyObject * ) newEulerObject( vec );
}
//***************************************************************************
//Begin Euler Util
static PyObject *M_Mathutils_CopyEuler( PyObject * self, PyObject * args )
{
EulerObject *eulU;
float *eul;
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];
return ( PyObject * ) newEulerObject( eul );
}
static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args )
{
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" ) );
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 );
}
//***************************************************************************
// Function: Mathutils_Init
//***************************************************************************
PyObject *Mathutils_Init( void )
{
PyObject *mod =
Py_InitModule3( "Blender.Mathutils", M_Mathutils_methods,
M_Mathutils_doc );
return ( mod );
}