diff options
author | Joseph Gilbert <ascotan@gmail.com> | 2004-02-29 16:20:34 +0300 |
---|---|---|
committer | Joseph Gilbert <ascotan@gmail.com> | 2004-02-29 16:20:34 +0300 |
commit | 8f3a9815baafb6f8fe00659cf6390a8c4092ef8b (patch) | |
tree | 9a69af7bffd6fd0d7da8e998d74a37dc273628a2 /source/blender/python/api2_2x/Mathutils.c | |
parent | 2255ac3b19ec3b2aa0e884ad5960f34c9c0efa23 (diff) |
Mathutils library for the python API
- support for quaternions, euler, vector, matrix operations.
- euler supports unique rotation calculation
- new matrix memory construction and internal functions
- quaternion slerp and diff calculation
- 2d, 3d, 4d vector construction and handling
- full conversion support between types
- update to object/window to reflect to matrix type
- update to types/blender/module to reflect new module
Diffstat (limited to 'source/blender/python/api2_2x/Mathutils.c')
-rw-r--r-- | source/blender/python/api2_2x/Mathutils.c | 1186 |
1 files changed, 1186 insertions, 0 deletions
diff --git a/source/blender/python/api2_2x/Mathutils.c b/source/blender/python/api2_2x/Mathutils.c new file mode 100644 index 00000000000..6f3863cec22 --- /dev/null +++ b/source/blender/python/api2_2x/Mathutils.c @@ -0,0 +1,1186 @@ +/* + * + * ***** 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, ¶m)) + 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); +} |