/* * * ***** 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); }