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 | |
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')
-rw-r--r-- | source/blender/python/api2_2x/Blender.c | 5 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Mathutils.c | 1186 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Mathutils.h | 205 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Object.c | 6 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Object.h | 1 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Types.c | 12 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Types.h | 6 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Window.c | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Window.h | 1 | ||||
-rw-r--r-- | source/blender/python/api2_2x/euler.c | 331 | ||||
-rw-r--r-- | source/blender/python/api2_2x/euler.h | 65 | ||||
-rw-r--r-- | source/blender/python/api2_2x/gen_utils.h | 4 | ||||
-rw-r--r-- | source/blender/python/api2_2x/matrix.c | 885 | ||||
-rw-r--r-- | source/blender/python/api2_2x/matrix.h | 77 | ||||
-rw-r--r-- | source/blender/python/api2_2x/modules.h | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/quat.c | 504 | ||||
-rw-r--r-- | source/blender/python/api2_2x/quat.h | 74 | ||||
-rw-r--r-- | source/blender/python/api2_2x/vector.c | 583 | ||||
-rw-r--r-- | source/blender/python/api2_2x/vector.h | 45 |
19 files changed, 3775 insertions, 219 deletions
diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c index a2de9891f1d..3f83185fc79 100644 --- a/source/blender/python/api2_2x/Blender.c +++ b/source/blender/python/api2_2x/Blender.c @@ -24,7 +24,7 @@ * * This is a new part of Blender. * - * Contributor(s): Michel Selten, Willian P. Germano + * Contributor(s): Michel Selten, Willian P. Germano, Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ @@ -220,7 +220,8 @@ void M_Blender_Init (void) PyDict_SetItemString (dict, "Curve", Curve_Init()); PyDict_SetItemString (dict, "Armature", Armature_Init()); PyDict_SetItemString (dict, "Ipo", Ipo_Init()); - PyDict_SetItemString (dict, "IpoCurve", IpoCurve_Init()); + PyDict_SetItemString (dict, "IpoCurve", IpoCurve_Init()); + PyDict_SetItemString (dict, "Mathutils",Mathutils_Init()); PyDict_SetItemString (dict, "Metaball", Metaball_Init()); PyDict_SetItemString (dict, "Image", Image_Init()); PyDict_SetItemString (dict, "Window", Window_Init()); 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); +} diff --git a/source/blender/python/api2_2x/Mathutils.h b/source/blender/python/api2_2x/Mathutils.h new file mode 100644 index 00000000000..1d4dd544dea --- /dev/null +++ b/source/blender/python/api2_2x/Mathutils.h @@ -0,0 +1,205 @@ +/* * ***** 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 ***** +*/ + +#ifndef EXPP_Mathutils_H +#define EXPP_Mathutils_H + +#include <Python.h> +#include <BKE_main.h> +#include <BKE_global.h> +#include <BKE_library.h> +#include <BKE_utildefines.h> +#include <BLI_blenlib.h> +#include <BLI_arithb.h> +#include <PIL_time.h> +#include <BLI_rand.h> +#include <math.h> +#include "vector.h" +#include "euler.h" +#include "quat.h" +#include "matrix.h" +#include "blendef.h" +#include "mydevice.h" +#include "constant.h" +#include "gen_utils.h" +#include "modules.h" +#include "Types.h" + + +/*****************************************************************************/ +// Python API function prototypes for the Mathutils module. +/*****************************************************************************/ +static PyObject *M_Mathutils_Rand (PyObject *self, PyObject *args); +static PyObject *M_Mathutils_Vector(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_CrossVecs(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_DotVecs (PyObject *self, PyObject *args); +static PyObject *M_Mathutils_AngleBetweenVecs(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_MidpointVecs(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_VecMultMat(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_ProjectVecs(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_CopyVec(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_Matrix(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_RotationMatrix(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_ScaleMatrix(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_ShearMatrix(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_TranslationMatrix(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_MatMultVec(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_CopyMat(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_Quaternion(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_CrossQuats(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_DotQuats(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_CopyQuat(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_DifferenceQuats(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_Slerp(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_Euler(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_CopyEuler(PyObject *self, PyObject *args); +static PyObject *M_Mathutils_RotateEuler(PyObject *self, PyObject *args); + +/*****************************************************************************/ +// The following string definitions are used for documentation strings. +// In Python these will be written to the console when doing a +// Blender.Mathutils.__doc__ Mathutils Module strings */ +/*****************************************************************************/ +static char M_Mathutils_doc[] = +"The Blender Mathutils module\n\n"; +static char M_Mathutils_Vector_doc[] = +"() - create a new vector object from a list of floats"; +static char M_Mathutils_Matrix_doc[] = +"() - create a new matrix object from a list of floats"; +static char M_Mathutils_Quaternion_doc[] = +"() - create a quaternion from a list or an axis of rotation and an angle"; +static char M_Mathutils_Euler_doc[] = +"() - create and return a new euler object"; +static char M_Mathutils_Rand_doc[] = +"() - return a random number"; +static char M_Mathutils_CrossVecs_doc[] = +"() - returns a vector perpedicular to the 2 vectors crossed"; +static char M_Mathutils_CopyVec_doc[] = +"() - create a copy of vector"; +static char M_Mathutils_DotVecs_doc[] = +"() - return the dot product of two vectors"; +static char M_Mathutils_AngleBetweenVecs_doc[] = +"() - returns the angle between two vectors in degrees"; +static char M_Mathutils_MidpointVecs_doc[] = +"() - return the vector to the midpoint between two vectors"; +static char M_Mathutils_MatMultVec_doc[] = +"() - multiplies a matrix by a column vector"; +static char M_Mathutils_VecMultMat_doc[] = +"() - multiplies a row vector by a matrix"; +static char M_Mathutils_ProjectVecs_doc[] = +"() - returns the projection vector from the projection of vecA onto vecB"; +static char M_Mathutils_RotationMatrix_doc[] = +"() - construct a rotation matrix from an angle and axis of rotation"; +static char M_Mathutils_ScaleMatrix_doc[] = +"() - construct a scaling matrix from a scaling factor"; +static char M_Mathutils_OrthoProjectionMatrix_doc[] = +"() - construct a orthographic projection matrix from a selected plane"; +static char M_Mathutils_ShearMatrix_doc[] = +"() - construct a shearing matrix from a plane of shear and a shear factor"; +static char M_Mathutils_CopyMat_doc[] = +"() - create a copy of a matrix"; +static char M_Mathutils_TranslationMatrix_doc[] = +"() - create a translation matrix from a vector"; +static char M_Mathutils_CopyQuat_doc[] = +"() - copy quatB to quatA"; +static char M_Mathutils_CopyEuler_doc[] = +"() - copy eulB to eultA"; +static char M_Mathutils_CrossQuats_doc[] = +"() - return the mutliplication of two quaternions"; +static char M_Mathutils_DotQuats_doc[] = +"() - return the dot product of two quaternions"; +static char M_Mathutils_Slerp_doc[] = +"() - returns the interpolation between two quaternions"; +static char M_Mathutils_DifferenceQuats_doc[] = +"() - return the angular displacment difference between two quats"; +static char M_Mathutils_RotateEuler_doc[] = +"() - rotate euler by an axis and angle"; + + +/*****************************************************************************/ +// Python method structure definition for Blender.Mathutils module: +/*****************************************************************************/ +struct PyMethodDef M_Mathutils_methods[] = { + {"Rand",(PyCFunction)M_Mathutils_Rand, METH_VARARGS, + M_Mathutils_Rand_doc}, + {"Vector",(PyCFunction)M_Mathutils_Vector, METH_VARARGS, + M_Mathutils_Vector_doc}, + {"CrossVecs",(PyCFunction)M_Mathutils_CrossVecs, METH_VARARGS, + M_Mathutils_CrossVecs_doc}, + {"DotVecs",(PyCFunction)M_Mathutils_DotVecs, METH_VARARGS, + M_Mathutils_DotVecs_doc}, + {"AngleBetweenVecs",(PyCFunction)M_Mathutils_AngleBetweenVecs, METH_VARARGS, + M_Mathutils_AngleBetweenVecs_doc}, + {"MidpointVecs",(PyCFunction)M_Mathutils_MidpointVecs, METH_VARARGS, + M_Mathutils_MidpointVecs_doc}, + {"VecMultMat",(PyCFunction)M_Mathutils_VecMultMat, METH_VARARGS, + M_Mathutils_VecMultMat_doc}, + {"ProjectVecs",(PyCFunction)M_Mathutils_ProjectVecs, METH_VARARGS, + M_Mathutils_ProjectVecs_doc}, + {"CopyVec",(PyCFunction)M_Mathutils_CopyVec, METH_VARARGS, + M_Mathutils_CopyVec_doc}, + {"Matrix",(PyCFunction)M_Mathutils_Matrix, METH_VARARGS, + M_Mathutils_Matrix_doc}, + {"RotationMatrix",(PyCFunction)M_Mathutils_RotationMatrix, METH_VARARGS, + M_Mathutils_RotationMatrix_doc}, + {"ScaleMatrix",(PyCFunction)M_Mathutils_ScaleMatrix, METH_VARARGS, + M_Mathutils_ScaleMatrix_doc}, + {"ShearMatrix",(PyCFunction)M_Mathutils_ShearMatrix, METH_VARARGS, + M_Mathutils_ShearMatrix_doc}, + {"TranslationMatrix",(PyCFunction)M_Mathutils_TranslationMatrix, METH_VARARGS, + M_Mathutils_TranslationMatrix_doc}, + {"CopyMat",(PyCFunction)M_Mathutils_CopyMat, METH_VARARGS, + M_Mathutils_CopyMat_doc}, + {"OrthoProjectionMatrix",(PyCFunction)M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, + M_Mathutils_OrthoProjectionMatrix_doc}, + {"MatMultVec",(PyCFunction)M_Mathutils_MatMultVec, METH_VARARGS, + M_Mathutils_MatMultVec_doc}, + {"Quaternion",(PyCFunction)M_Mathutils_Quaternion, METH_VARARGS, + M_Mathutils_Quaternion_doc}, + {"CopyQuat",(PyCFunction)M_Mathutils_CopyQuat, METH_VARARGS, + M_Mathutils_CopyQuat_doc}, + {"CrossQuats",(PyCFunction)M_Mathutils_CrossQuats, METH_VARARGS, + M_Mathutils_CrossQuats_doc}, + {"DotQuats",(PyCFunction)M_Mathutils_DotQuats, METH_VARARGS, + M_Mathutils_DotQuats_doc}, + {"DifferenceQuats",(PyCFunction)M_Mathutils_DifferenceQuats, METH_VARARGS, + M_Mathutils_DifferenceQuats_doc}, + {"Slerp",(PyCFunction)M_Mathutils_Slerp, METH_VARARGS, + M_Mathutils_Slerp_doc}, + {"Euler",(PyCFunction)M_Mathutils_Euler, METH_VARARGS, + M_Mathutils_Euler_doc}, + {"CopyEuler",(PyCFunction)M_Mathutils_CopyEuler, METH_VARARGS, + M_Mathutils_CopyEuler_doc}, + {"RotateEuler",(PyCFunction)M_Mathutils_RotateEuler, METH_VARARGS, + M_Mathutils_RotateEuler_doc}, + {NULL, NULL, 0, NULL} +}; + +#endif /* EXPP_Mathutils_H */ diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index b2852438484..7fbcd670455 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -750,9 +750,9 @@ static PyObject *Object_getEuler (BPy_Object *self) static PyObject *Object_getInverseMatrix (BPy_Object *self) { - MatrixObject *inverse = (MatrixObject *)newMatrixObject (NULL); + MatrixObject *inverse = (MatrixObject *)newMatrixObject(NULL, 4, 4); - Mat4Invert (inverse->mem, self->object->obmat); + Mat4Invert (*inverse->matrix, self->object->obmat); return ((PyObject *)inverse); @@ -796,7 +796,7 @@ static PyObject *Object_getMatrix (BPy_Object *self) ob = self->object; - return (newMatrixObject (ob->obmat)); + return (PyObject*)newMatrixObject((float*)ob->obmat, 4, 4); } static PyObject *Object_getName (BPy_Object *self) diff --git a/source/blender/python/api2_2x/Object.h b/source/blender/python/api2_2x/Object.h index d2954e78630..b2d5fc34c77 100644 --- a/source/blender/python/api2_2x/Object.h +++ b/source/blender/python/api2_2x/Object.h @@ -60,6 +60,7 @@ #include "gen_utils.h" #include "modules.h" #include "vector.h" +#include "matrix.h" /* The Object PyType Object defined in Object.c */ extern PyTypeObject Object_Type; diff --git a/source/blender/python/api2_2x/Types.c b/source/blender/python/api2_2x/Types.c index 0a45ceb89df..0bcf6b5afe0 100644 --- a/source/blender/python/api2_2x/Types.c +++ b/source/blender/python/api2_2x/Types.c @@ -24,13 +24,17 @@ * * This is a new part of Blender. * - * Contributor(s): Willian P. Germano, Alex Mole + * Contributor(s): Willian P. Germano, Alex Mole, Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include "Types.h" +char M_Types_doc[] = +"The Blender Types module\n\n\ +This module is a dictionary of all Blender Python types"; + struct PyMethodDef Null_methods[] = {{NULL, NULL}}; /*****************************************************************************/ @@ -44,7 +48,10 @@ PyObject *Types_Init (void) * do it now, we get an easy way to crash Blender. Maybe we'd better * have an Init function for all these internal types that more than one * module can use. We could call it after setting the Blender dictionary */ + matrix_Type.ob_type = &PyType_Type; vector_Type.ob_type = &PyType_Type; + euler_Type.ob_type = &PyType_Type; + quaternion_Type.ob_type = &PyType_Type; rgbTuple_Type.ob_type = &PyType_Type; constant_Type.ob_type = &PyType_Type; buffer_Type.ob_type = &PyType_Type; @@ -100,6 +107,9 @@ PyObject *Types_Init (void) PyDict_SetItemString(dict, "bufferType", (PyObject *)&buffer_Type); PyDict_SetItemString(dict, "constantType", (PyObject *)&constant_Type); PyDict_SetItemString(dict, "rgbTupleType", (PyObject *)&rgbTuple_Type); + PyDict_SetItemString(dict, "matrix_Type", (PyObject *)&matrix_Type); + PyDict_SetItemString(dict, "eulerType", (PyObject *)&euler_Type); + PyDict_SetItemString(dict, "quaternionType", (PyObject *)&quaternion_Type); PyDict_SetItemString(dict, "BezTripleType", (PyObject *)&BezTriple_Type); return submodule; diff --git a/source/blender/python/api2_2x/Types.h b/source/blender/python/api2_2x/Types.h index ea098cfb3eb..595f04d0383 100644 --- a/source/blender/python/api2_2x/Types.h +++ b/source/blender/python/api2_2x/Types.h @@ -46,11 +46,9 @@ extern PyTypeObject Armature_Type, Bone_Type; extern PyTypeObject Curve_Type, Ipo_Type, Metaball_Type; extern PyTypeObject Lattice_Type; -extern PyTypeObject vector_Type, buffer_Type, rgbTuple_Type, +extern PyTypeObject buffer_Type, rgbTuple_Type, constant_Type, BezTriple_Type; -static char M_Types_doc[] = -"The Blender Types module\n\n\ -This module is a dictionary of all Blender Python types"; +extern PyTypeObject vector_Type, matrix_Type, euler_Type, quaternion_Type; #endif /* EXPP_TYPES_H */ diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index a7897f56dcd..6a691515b41 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -327,7 +327,7 @@ static PyObject *M_Window_GetViewMatrix(PyObject *self) return Py_None; } - viewmat = newMatrixObject (G.vd->viewmat); + viewmat = (PyObject*)newMatrixObject((float*)G.vd->viewmat, 4, 4); if (!viewmat) return (EXPP_ReturnPyObjError (PyExc_MemoryError, diff --git a/source/blender/python/api2_2x/Window.h b/source/blender/python/api2_2x/Window.h index c7b631a703a..800254b47df 100644 --- a/source/blender/python/api2_2x/Window.h +++ b/source/blender/python/api2_2x/Window.h @@ -52,6 +52,7 @@ #include "gen_utils.h" #include "modules.h" +#include "matrix.h" /* Used in Draw.c */ extern int EXPP_disable_force_draw; diff --git a/source/blender/python/api2_2x/euler.c b/source/blender/python/api2_2x/euler.c new file mode 100644 index 00000000000..c6c8d61f9f3 --- /dev/null +++ b/source/blender/python/api2_2x/euler.c @@ -0,0 +1,331 @@ +/* + * + * ***** 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. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "euler.h" + +//doc strings +char Euler_Zero_doc[] = +"() - set all values in the euler to 0"; +char Euler_Unique_doc[] = +"() - sets the euler rotation a unique shortest arc rotation - tests for gimbal lock"; +char Euler_ToMatrix_doc[] = +"() - returns a rotation matrix representing the euler rotation"; +char Euler_ToQuat_doc[] = +"() - returns a quaternion representing the euler rotation"; + +//methods table +struct PyMethodDef Euler_methods[] = { + {"zero",(PyCFunction)Euler_Zero, METH_NOARGS, + Euler_Zero_doc}, + {"unique",(PyCFunction)Euler_Unique, METH_NOARGS, + Euler_Unique_doc}, + {"toMatrix",(PyCFunction)Euler_ToMatrix, METH_NOARGS, + Euler_ToMatrix_doc}, + {"toQuat",(PyCFunction)Euler_ToQuat, METH_NOARGS, + Euler_ToQuat_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************/ +// Euler Python Object +/*****************************/ + +//euler methods +PyObject *Euler_ToQuat(EulerObject *self) +{ + float *quat; + int x; + + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(Py_PI/180); + } + quat = PyMem_Malloc(4*sizeof(float)); + EulToQuat(self->eul, quat); + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(180/Py_PI); + } + return (PyObject*)newQuaternionObject(quat); +} + +PyObject *Euler_ToMatrix(EulerObject *self) +{ + float *mat; + int x; + + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(Py_PI/180); + } + mat = PyMem_Malloc(3*3*sizeof(float)); + EulToMat3(self->eul, (float(*)[3])mat); + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(180/Py_PI); + } + return (PyObject*)newMatrixObject(mat,3,3); +} + +PyObject *Euler_Unique(EulerObject *self) +{ + float heading, pitch, bank; + float pi2 = (float)Py_PI * 2.0f; + float piO2 = (float)Py_PI / 2.0f; + float Opi2 = 1.0f / pi2; + + //radians + heading = self->eul[0] * (float)(Py_PI/180); + pitch = self->eul[1] * (float)(Py_PI/180); + bank = self->eul[2] * (float)(Py_PI/180); + + //wrap heading in +180 / -180 + pitch += (float)Py_PI; + pitch -= (float)floor(pitch * Opi2) * pi2; + pitch -= (float)Py_PI; + + + if(pitch < -piO2){ + pitch = (float)-Py_PI - pitch; + heading += (float)Py_PI; + bank += (float)Py_PI; + }else if (pitch > piO2){ + pitch = (float)Py_PI - pitch; + heading += (float)Py_PI; + bank += (float)Py_PI; + } + + //gimbal lock test + if(fabs(pitch) > piO2 - 1e-4){ + heading += bank; + bank = 0.0f; + }else{ + bank += (float)Py_PI; + bank -= (float)(floor(bank * Opi2)) * pi2; + bank -= (float)Py_PI; + } + + heading += (float)Py_PI; + heading -= (float)(floor(heading * Opi2)) * pi2; + heading -= (float)Py_PI; + + //back to degrees + self->eul[0] = heading * (float)(180/Py_PI); + self->eul[1] = pitch * (float)(180/Py_PI); + self->eul[2] = bank * (float)(180/Py_PI); + + return EXPP_incr_ret(Py_None); +} + +PyObject *Euler_Zero(EulerObject *self) +{ + self->eul[0] = 0.0; + self->eul[1] = 0.0; + self->eul[2] = 0.0; + + return EXPP_incr_ret(Py_None); +} + +static void Euler_dealloc(EulerObject *self) +{ + PyObject_DEL (self); +} + +static PyObject *Euler_getattr(EulerObject *self, char *name) +{ + if (ELEM3(name[0], 'x', 'y', 'z') && name[1]==0){ + return PyFloat_FromDouble(self->eul[name[0]-'x']); + } + return Py_FindMethod(Euler_methods, (PyObject*)self, name); +} + +static int Euler_setattr(EulerObject *self, char *name, PyObject *e) +{ + float val; + + if (!PyArg_Parse(e, "f", &val)) + return EXPP_ReturnIntError(PyExc_TypeError, + "unable to parse float argument\n"); + + if (ELEM3(name[0], 'x', 'y', 'z') && name[1]==0){ + self->eul[name[0]-'x']= val; + return 0; + } + else return -1; +} + +/* Eulers Sequence methods */ +static PyObject *Euler_item(EulerObject *self, int i) +{ + if (i < 0 || i >= 3) + return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); + + return Py_BuildValue("f", self->eul[i]); +} + +static PyObject *Euler_slice(EulerObject *self, int begin, int end) +{ + PyObject *list; + int count; + + if (begin < 0) begin= 0; + if (end > 3) end= 3; + if (begin > end) begin= end; + + list= PyList_New(end-begin); + + for (count = begin; count < end; count++){ + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->eul[count])); + } + return list; +} + +static int Euler_ass_item(EulerObject *self, int i, PyObject *ob) +{ + if (i < 0 || i >= 3) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + + if (!PyNumber_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "Euler member must be a number\n"); + + if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + self->eul[i]= (float)PyFloat_AsDouble(ob); + } + return 0; +} + +static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq) +{ + int count, z; + + if (begin < 0) begin= 0; + if (end > 3) end= 3; + if (begin > end) begin= end; + + if (!PySequence_Check(seq)) + return EXPP_ReturnIntError(PyExc_TypeError, + "illegal argument type for built-in operation\n"); + if (PySequence_Length(seq) != (end - begin)) + return EXPP_ReturnIntError(PyExc_TypeError, + "size mismatch in slice assignment\n"); + + z = 0; + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, z); z++; + + if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ + Py_DECREF(ob); + return -1; + }else{ + if (!PyArg_Parse(ob, "f", &self->eul[count])) { + Py_DECREF(ob); + return -1; + } + } + } + return 0; +} + +static PyObject *Euler_repr (EulerObject *self) +{ + int i, maxindex = 3 - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString ("["); + + for (i = 0; i < maxindex; i++) { + sprintf(ftoa, "%.4f, ", self->eul[i]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + } + + sprintf(ftoa, "%.4f]\n", self->eul[maxindex]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + + if (str1) return str1; + +error: + Py_XDECREF (str1); + Py_XDECREF (str2); + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyString!\n"); +} + +static PySequenceMethods Euler_SeqMethods = +{ + (inquiry) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Euler_item, /* sq_item */ + (intintargfunc) Euler_slice, /* sq_slice */ + (intobjargproc) Euler_ass_item, /* sq_ass_item */ + (intintobjargproc) Euler_ass_slice, /* sq_ass_slice */ +}; + +PyTypeObject euler_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "euler", /*tp_name*/ + sizeof(EulerObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor) Euler_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) Euler_getattr, /*tp_getattr*/ + (setattrfunc) Euler_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Euler_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &Euler_SeqMethods, /*tp_as_sequence*/ +}; + +PyObject *newEulerObject(float *eul) +{ + EulerObject *self; + int x; + + euler_Type.ob_type = &PyType_Type; + + self = PyObject_NEW(EulerObject, &euler_Type); + + if(!eul){ + self->eul = PyMem_Malloc (3*sizeof (float)); + for(x = 0; x < 3; x++){ + self->eul[x] = 0.0f; + } + }else self->eul = eul; + + return (PyObject*) self; +} + diff --git a/source/blender/python/api2_2x/euler.h b/source/blender/python/api2_2x/euler.h new file mode 100644 index 00000000000..2e33c7cf350 --- /dev/null +++ b/source/blender/python/api2_2x/euler.h @@ -0,0 +1,65 @@ +/* * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_euler_h +#define EXPP_euler_h + +#include "Python.h" +#include "gen_utils.h" +#include "Types.h" +#include <BLI_arithb.h> +#include "quat.h" +#include "matrix.h" +#include "BKE_utildefines.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/*****************************/ +// Euler Python Object +/*****************************/ + +#define EulerObject_Check(v) ((v)->ob_type == &euler_Type) + +typedef struct { + PyObject_VAR_HEAD + float * eul; +} EulerObject; + +//prototypes +PyObject *newEulerObject(float *eul); +PyObject *Euler_Zero(EulerObject *self); +PyObject *Euler_Unique(EulerObject *self); +PyObject *Euler_ToMatrix(EulerObject *self); +PyObject *Euler_ToQuat(EulerObject *self); + +#endif /* EXPP_euler_h */ + diff --git a/source/blender/python/api2_2x/gen_utils.h b/source/blender/python/api2_2x/gen_utils.h index 6418c9638a3..efeb0a43370 100644 --- a/source/blender/python/api2_2x/gen_utils.h +++ b/source/blender/python/api2_2x/gen_utils.h @@ -24,7 +24,7 @@ * * This is a new part of Blender. * - * Contributor(s): Michel Selten, Willian P. Germano, Alex Mole + * Contributor(s): Michel Selten, Willian P. Germano, Alex Mole, Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ @@ -48,6 +48,8 @@ #include <DNA_scriptlink_types.h> #include <DNA_listBase.h> +#define Py_PI 3.14159265358979323846 + int StringEqual (const char * string1, const char * string2); char * GetIdName (ID *id); ID *GetIdFromList(ListBase *list, char *name); diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c index 76d4409dbad..fcabc1c1c48 100644 --- a/source/blender/python/api2_2x/matrix.c +++ b/source/blender/python/api2_2x/matrix.c @@ -22,59 +22,427 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * Contributor(s): Michel Selten + * Contributor(s): Michel Selten & Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -/* This file is the old bpython opy_matrix.c with minor modifications */ +#include "matrix.h" -#include "vector.h" -#include "BLI_arithb.h" +//doc strings +char Matrix_Zero_doc[] = +"() - set all values in the matrix to 0"; +char Matrix_Identity_doc[] = +"() - set the square matrix to it's identity matrix"; +char Matrix_Transpose_doc[] = +"() - set the matrix to it's transpose"; +char Matrix_Determinant_doc[] = +"() - return the determinant of the matrix"; +char Matrix_Invert_doc[] = +"() - set the matrix to it's inverse if an inverse is possible"; +char Matrix_TranslationPart_doc[] = +"() - return a vector encompassing the translation of the matrix"; +char Matrix_RotationPart_doc[] = +"() - return a vector encompassing the rotation of the matrix"; +char Matrix_Resize4x4_doc[] = +"() - resize the matrix to a 4x4 square matrix"; +char Matrix_toEuler_doc[] = +"() - convert matrix to a euler angle rotation"; +char Matrix_toQuat_doc[] = +"() - convert matrix to a quaternion rotation"; -static void Matrix_dealloc (MatrixObject *self) +//methods table +struct PyMethodDef Matrix_methods[] = { + {"zero",(PyCFunction)Matrix_Zero, METH_NOARGS, + Matrix_Zero_doc}, + {"identity",(PyCFunction)Matrix_Identity, METH_NOARGS, + Matrix_Identity_doc}, + {"transpose",(PyCFunction)Matrix_Transpose, METH_NOARGS, + Matrix_Transpose_doc}, + {"determinant",(PyCFunction)Matrix_Determinant, METH_NOARGS, + Matrix_Determinant_doc}, + {"invert",(PyCFunction)Matrix_Invert, METH_NOARGS, + Matrix_Invert_doc}, + {"translationPart",(PyCFunction)Matrix_TranslationPart, METH_NOARGS, + Matrix_TranslationPart_doc}, + {"rotationPart",(PyCFunction)Matrix_RotationPart, METH_NOARGS, + Matrix_RotationPart_doc}, + {"resize4x4",(PyCFunction)Matrix_Resize4x4, METH_NOARGS, + Matrix_Resize4x4_doc}, + {"toEuler",(PyCFunction)Matrix_toEuler, METH_NOARGS, + Matrix_toEuler_doc}, + {"toQuat",(PyCFunction)Matrix_toQuat, METH_NOARGS, + Matrix_toQuat_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************/ +// Matrix Python Object +/*****************************/ + +PyObject *Matrix_toQuat(MatrixObject *self) { - Py_DECREF (self->rows[0]); - Py_DECREF (self->rows[1]); - Py_DECREF (self->rows[2]); - Py_DECREF (self->rows[3]); + float *quat, *mat; - if (self->mem) - PyMem_Free (self->mem); - PyMem_DEL (self); + if(self->colSize < 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + }else if (self->colSize > 2){ //3 or 4 col + if(self->rowSize < 3) //3 or 4 row + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + + mat = PyMem_Malloc(3*3*sizeof(float)); + mat[0] = self->matrix[0][0]; mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; + } + quat = PyMem_Malloc(4*sizeof(float)); + Mat3ToQuat((float(*)[3])mat,quat); + + return (PyObject*)newQuaternionObject(quat); } -static PyObject * Matrix_getattr (MatrixObject *self, char *name) + +PyObject *Matrix_toEuler(MatrixObject *self) { - PyObject * list; - float val[3]; - float mat3[3][3]; + float *eul, *mat; + int x; - if (strcmp (name, "rot") == 0) - { - Mat3CpyMat4 (mat3, self->mat); - Mat3ToEul (mat3, val); - } - else if (strcmp (name, "size") == 0) - { - Mat4ToSize (self->mat, val); + if(self->colSize < 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + }else if (self->colSize > 2){ //3 or 4 col + if(self->rowSize < 3) //3 or 4 row + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + + mat = PyMem_Malloc(3*3*sizeof(float)); + mat[0] = self->matrix[0][0]; mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; + } + eul = PyMem_Malloc(3*sizeof(float)); + Mat3ToEul((float(*)[3])mat,eul); + + for(x = 0; x < 3; x++){ + eul[x] *= (float)(180/Py_PI); + } + + return (PyObject*)newEulerObject(eul); +} + +PyObject *Matrix_Resize4x4(MatrixObject *self) +{ + float *mat; + float * contigPtr; + int x, row, col; + + if(self->colSize == 4 && self->rowSize == 4) + return EXPP_incr_ret(Py_None); + + mat = PyMem_Malloc(4*4*sizeof(float)); + for(x = 0; x < 16; x++){ + mat[x] = 0.0f; + } + + if(self->colSize == 2){ //2x2, 2x3, 2x4 + mat[0] = self->matrix[0][0];mat[1] = self->matrix[0][1]; + mat[4] = self->matrix[1][0];mat[5] = self->matrix[1][1]; + if (self->rowSize > 2){ + mat[8] = self->matrix[2][0];mat[9] = self->matrix[2][1]; + } + if (self->rowSize > 3){ + mat[12] = self->matrix[3][0];mat[13] = self->matrix[3][1]; + } + mat[10] = 1.0f; mat[15] = 1.0f; + }else if (self->colSize == 3){ //3x2, 3x3, 3x4 + mat[0] = self->matrix[0][0];mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2];mat[4] = self->matrix[1][0]; + mat[5] = self->matrix[1][1];mat[6] = self->matrix[1][2]; + if (self->rowSize > 2){ + mat[8] = self->matrix[2][0];mat[9] = self->matrix[2][1]; + mat[10] = self->matrix[2][2]; + } + if (self->rowSize > 3){ + mat[12] = self->matrix[3][0];mat[13] = self->matrix[3][1]; + mat[14] = self->matrix[3][2]; + } + if(self->rowSize == 2) mat[10] = 1.0f; + mat[15] = 1.0f; + }else if (self->colSize == 4){ //2x4, 3x4 + mat[0] = self->matrix[0][0];mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2];mat[3] = self->matrix[0][3]; + mat[4] = self->matrix[1][0];mat[5] = self->matrix[1][1]; + mat[6] = self->matrix[1][2];mat[7] = self->matrix[1][3]; + if (self->rowSize > 2 + ){ + mat[8] = self->matrix[2][0];mat[9] = self->matrix[2][1]; + mat[10] = self->matrix[2][2];mat[11] = self->matrix[2][3]; + } + if(self->rowSize == 2) mat[10] = 1.0f; + mat[15] = 1.0f; + } + + PyMem_Free(*self->matrix); + contigPtr = PyMem_Malloc(4 * 4 * sizeof(float)); + if(contigPtr == NULL){ + return (EXPP_ReturnPyObjError (PyExc_MemoryError, + "problem allocating array space\n\n")); + } + self->matrix = PyMem_Malloc(4* sizeof(float*)); + if(self->matrix == NULL){ + return (EXPP_ReturnPyObjError (PyExc_MemoryError, + "problem allocating pointer space\n\n")); + } + for (x = 0; x < 4; x++){ + self->matrix[x] = contigPtr + (x *4); } - else if (strcmp (name, "loc") == 0) - { - VECCOPY (val, (float *)(self->mat)[3]); + + for (row = 0; row < 4; row++){ + for(col = 0; col < 4; col++){ + self->matrix[row][col] = mat[(row * 4) + col]; + } + } + PyMem_Free(mat); + + self->colSize = 4; + self->rowSize = 4; + + return EXPP_incr_ret(Py_None); +} + +PyObject *Matrix_TranslationPart(MatrixObject *self) +{ + float *vec; + + if(self->colSize < 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + }else if (self->colSize > 2){ //3 or 4 columns + if(self->rowSize < 4) //all 4 rows + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + + vec = PyMem_Malloc(3 * sizeof(float)); + vec[0] = self->matrix[3][0]; + vec[1] = self->matrix[3][1]; + vec[2] = self->matrix[3][2]; + } + + return (PyObject*)newVectorObject(vec,3); +} + +PyObject *Matrix_RotationPart(MatrixObject *self) +{ + float *mat; + + if(self->colSize < 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + }else if (self->colSize > 2){ //3 or 4 col + if(self->rowSize < 3) //3 or 4 row + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "inappropriate matrix size\n"); + + mat = PyMem_Malloc(3*3*sizeof(float)); + mat[0] = self->matrix[0][0]; mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; + } + + return (PyObject*)newMatrixObject(mat,3,3); +} + +PyObject *Matrix_Invert(MatrixObject *self) +{ + float det; + int x,y,z; + float *mat; + float t; + + if(self->rowSize != self->colSize) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "only square matrices are supported\n"); + + //calculate the determinant + if(self->rowSize == 2){ + det = Det2x2(self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1]); + }else if(self->rowSize == 3){ + det = Det3x3(self->matrix[0][0], self->matrix[0][1], + self->matrix[0][2], self->matrix[1][0], + self->matrix[1][1], self->matrix[1][2], + self->matrix[2][0], self->matrix[2][1], + self->matrix[2][2]); + }else if(self->rowSize == 4){ + det = Det4x4(*self->matrix); + }else{ + return EXPP_ReturnPyObjError(PyExc_StandardError, + "error calculating determinant for inverse()\n"); + } + + if(det != 0){ + + //calculate the classical adjoint + if(self->rowSize == 2){ + mat = PyMem_Malloc(self->rowSize * self->colSize * sizeof(float)); + mat[0] = self->matrix[1][1]; + mat[1] = -self->matrix[1][0]; + mat[2] = -self->matrix[0][1]; + mat[3] = self->matrix[0][0]; + }else if(self->rowSize == 3){ + mat = PyMem_Malloc(self->rowSize * self->colSize * sizeof(float)); + Mat3Adj((float(*)[3])mat, *self->matrix); + }else if (self->rowSize == 4){ + mat = PyMem_Malloc(self->rowSize * self->colSize * sizeof(float)); + Mat4Adj((float(*)[4])mat, *self->matrix); + } + + //divide by determinate + for(x = 0; x < (self->rowSize * self->colSize); x++){ + mat[x] /= det; + } + + //set values + z = 0; + for(x = 0; x < self->rowSize; x++){ + for(y = 0; y < self->colSize; y++){ + self->matrix[x][y] = mat[z]; + z++; + } + } + + //transpose + if(self->rowSize == 2){ + t = self->matrix[1][0]; + self->matrix[1][0] = self->matrix[0][1]; + self->matrix[0][1] = t; + }else if(self->rowSize == 3){ + Mat3Transp((float(*)[3])mat); + } + else if (self->rowSize == 4){ + Mat4Transp((float(*)[4])mat); + } + }else{ + printf("matrix does not have an inverse - none attempted\n"); + } + + return EXPP_incr_ret(Py_None); +} + + +PyObject *Matrix_Determinant(MatrixObject *self) +{ + float det; + + if(self->rowSize != self->colSize) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "only square matrices are supported\n"); + + if(self->rowSize == 2){ + det = Det2x2(self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1]); + }else if(self->rowSize == 3){ + det = Det3x3(self->matrix[0][0], self->matrix[0][1], + self->matrix[0][2], self->matrix[1][0], + self->matrix[1][1], self->matrix[1][2], + self->matrix[2][0], self->matrix[2][1], + self->matrix[2][2]); + }else if(self->rowSize == 4){ + det = Det4x4(*self->matrix); + }else{ + return EXPP_ReturnPyObjError(PyExc_StandardError, + "error in determinant()\n"); + } + return PyFloat_FromDouble(det); +} + +PyObject *Matrix_Transpose(MatrixObject *self) +{ + float t; + + if(self->rowSize != self->colSize) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "only square matrices are supported\n"); + + if(self->rowSize == 2){ + t = self->matrix[1][0]; + self->matrix[1][0] = self->matrix[0][1]; + self->matrix[0][1] = t; + } + else if(self->rowSize == 3){ + Mat3Transp(*self->matrix); + } + else if (self->rowSize == 4){ + Mat4Transp(*self->matrix); + } + else + return (EXPP_ReturnPyObjError (PyExc_TypeError, + "unable to transpose matrix\n")); + + return EXPP_incr_ret(Py_None); +} + +PyObject *Matrix_Zero(MatrixObject *self) +{ + int row, col; + + for (row = 0; row < self->rowSize; row++){ + for (col = 0; col < self->colSize; col++){ + self->matrix[row][col] = 0.0f; + } + } + return EXPP_incr_ret(Py_None); +} + +PyObject *Matrix_Identity(MatrixObject *self) +{ + if(self->rowSize != self->colSize) + return (EXPP_ReturnPyObjError(PyExc_AttributeError, + "only square matrices supported\n")); + + if(self->rowSize == 2){ + self->matrix[0][0] = 1.0f; + self->matrix[0][1] = 0.0f; + self->matrix[1][0] = 0.0f; + self->matrix[1][1] = 1.0f; + } + else if(self->rowSize == 3){ + Mat3One(*self->matrix); + } + else if (self->rowSize == 4){ + Mat4One(*self->matrix); + } + else + return (EXPP_ReturnPyObjError (PyExc_TypeError, + "unable to create identity matrix\n")); + + return EXPP_incr_ret(Py_None); +} + +static void Matrix_dealloc (MatrixObject *self) +{ + PyMem_Free (self->matrix); + PyMem_DEL (self); +} + +static PyObject * Matrix_getattr (MatrixObject *self, char *name) +{ + if (strcmp (name, "rowSize") == 0){ + return PyInt_FromLong((long)self->rowSize); } - else - { - return (EXPP_ReturnPyObjError (PyExc_AttributeError, - "expected 'rot', 'size' or 'loc'")); + else if (strcmp (name, "colSize") == 0){ + return PyInt_FromLong((long)self->colSize); } - list = PyList_New (3); - PyList_SetItem (list, 0, PyFloat_FromDouble (val[0])); - PyList_SetItem (list, 1, PyFloat_FromDouble (val[1])); - PyList_SetItem (list, 2, PyFloat_FromDouble (val[2])); - - return (list); + return Py_FindMethod(Matrix_methods, (PyObject*)self, name); } static int Matrix_setattr (MatrixObject *self, char *name, PyObject *v) @@ -85,80 +453,435 @@ static int Matrix_setattr (MatrixObject *self, char *name, PyObject *v) static PyObject * Matrix_repr (MatrixObject *self) { - return (EXPP_tuple_repr ((PyObject *) self, 4)); + PyObject *repr, *str; + int x,y; + char ftoa[24]; + + repr = PyString_FromString(""); + if (!repr) + return (EXPP_ReturnPyObjError (PyExc_AttributeError, + "Attribute error in PyMatrix (repr)\n")); + + for(x = 0; x < self->rowSize; x++){ + str = PyString_FromString ("["); + PyString_ConcatAndDel(&repr,str); + + for(y = 0; y < (self->colSize - 1); y++){ + sprintf(ftoa, "%.4f, ", self->matrix[x][y]); + str = PyString_FromString (ftoa); + PyString_ConcatAndDel(&repr,str); + } + sprintf(ftoa, "%.4f]\n", self->matrix[x][y]); + str = PyString_FromString (ftoa); + PyString_ConcatAndDel(&repr,str); + } + return repr; } +//no support for matrix[x][y] so have to return by sequence index static PyObject * Matrix_item (MatrixObject *self, int i) { - if ((i<0) || (i>=4)) - { - return (EXPP_ReturnPyObjError (PyExc_IndexError, - "array index out of range")); - } - return (EXPP_incr_ret (self->rows[i])); + int maxsize, x, y; + + maxsize = self->colSize * self->rowSize; + if(i < 0 || i >= maxsize) + return EXPP_ReturnPyObjError(PyExc_IndexError, + "array index out of range\n"); + + x = (int)floor((double)(i / self->colSize)); + y = i % self->colSize; + + return PyFloat_FromDouble(self->matrix[x][y]); +} + +static PyObject *Matrix_slice(MatrixObject *self, int begin, int end) +{ + PyObject *list; + int count, maxsize, x, y; + + maxsize = self->colSize * self->rowSize; + if (begin < 0) begin= 0; + if (end > maxsize) end= maxsize; + if (begin > end) begin= end; + + list= PyList_New(end-begin); + + for (count = begin; count < end; count++){ + x = (int)floor((double)(count / self->colSize)); + y = count % self->colSize; + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->matrix[x][y])); + } + + return list; +} + +static int Matrix_ass_item(MatrixObject *self, int i, PyObject *ob) +{ + int maxsize, x, y; + + maxsize = self->colSize * self->rowSize; + if (i < 0 || i >= maxsize) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + if (!PyInt_Check(ob) && !PyFloat_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "matrix member must be a number\n"); + + x = (int)floor((double)(i / self->colSize)); + y = i % self->colSize; + self->matrix[x][y] = (float)PyFloat_AsDouble(ob); + + return 0; +} + +static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *seq) +{ + int count, maxsize, x, y, z; + + maxsize = self->colSize * self->rowSize; + if (begin < 0) begin= 0; + if (end > maxsize) end= maxsize; + if (begin > end) begin= end; + + if (!PySequence_Check(seq)) + return EXPP_ReturnIntError(PyExc_TypeError, + "illegal argument type for built-in operation\n"); + if (PySequence_Length(seq) != (end - begin)) + return EXPP_ReturnIntError(PyExc_TypeError, + "size mismatch in slice assignment\n"); + + z = 0; + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, z); z++; + if (!PyInt_Check(ob) && !PyFloat_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "list member must be a number\n"); + + x = (int)floor((double)(count / self->colSize)); + y = count % self->colSize; + if (!PyArg_Parse(ob, "f", &self->matrix[x][y])){ + Py_DECREF(ob); + return -1; + } + } + return 0; +} + +static int Matrix_len(MatrixObject *self) +{ + return (self->colSize * self->rowSize); +} + +PyObject * Matrix_add(PyObject *m1, PyObject * m2) +{ + float * mat; + int matSize, rowSize, colSize, x,y; + + if((!Matrix_CheckPyObject(m1)) || (!Matrix_CheckPyObject(m2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + + if(((MatrixObject*)m1)->flag > 0 || ((MatrixObject*)m2)->flag > 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot add scalar to a matrix\n"); + + if(((MatrixObject*)m1)->rowSize!= ((MatrixObject*)m2)->rowSize || + ((MatrixObject*)m1)->colSize != ((MatrixObject*)m2)->colSize) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "matrices must be the same same for this operation\n"); + + rowSize = (((MatrixObject*)m1)->rowSize); + colSize = (((MatrixObject*)m1)->colSize); + matSize = rowSize * colSize; + + mat = PyMem_Malloc (matSize * sizeof(float)); + + for(x = 0; x < rowSize; x++){ + for(y = 0; y < colSize; y++){ + mat[((x * rowSize) + y)] = + ((MatrixObject*)m1)->matrix[x][y] + + ((MatrixObject*)m2)->matrix[x][y]; + } + } + + return newMatrixObject(mat, rowSize, colSize); } +PyObject * Matrix_sub(PyObject *m1, PyObject * m2) +{ + float * mat; + int matSize, rowSize, colSize, x,y; + + if((!Matrix_CheckPyObject(m1)) || (!Matrix_CheckPyObject(m2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + + if(((MatrixObject*)m1)->flag > 0 || ((MatrixObject*)m2)->flag > 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot subtract a scalar from a matrix\n"); + + if(((MatrixObject*)m1)->rowSize!= ((MatrixObject*)m2)->rowSize || + ((MatrixObject*)m1)->colSize != ((MatrixObject*)m2)->colSize) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "matrices must be the same same for this operation\n"); + + rowSize = (((MatrixObject*)m1)->rowSize); + colSize = (((MatrixObject*)m1)->colSize); + matSize = rowSize * colSize; + + mat = PyMem_Malloc (matSize * sizeof(float)); + + for(x = 0; x < rowSize; x++){ + for(y = 0; y < colSize; y++){ + mat[((x * rowSize) + y)] = + ((MatrixObject*)m1)->matrix[x][y] - + ((MatrixObject*)m2)->matrix[x][y]; + } + } + + return newMatrixObject(mat, rowSize, colSize); +} + +PyObject * Matrix_mul(PyObject *m1, PyObject * m2) +{ + float * mat; + int matSizeV, rowSizeV, colSizeV, rowSizeW, colSizeW, matSizeW, x, y, z; + float dot = 0; + MatrixObject * matV; + MatrixObject * matW; + + if((!Matrix_CheckPyObject(m1)) || (!Matrix_CheckPyObject(m2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + + //get some vars + rowSizeV = (((MatrixObject*)m1)->rowSize); + colSizeV = (((MatrixObject*)m1)->colSize); + matSizeV = rowSizeV * colSizeV; + rowSizeW = (((MatrixObject*)m2)->rowSize); + colSizeW = (((MatrixObject*)m2)->colSize); + matSizeW = rowSizeW * colSizeW; + matV = ((MatrixObject*)m1); + matW = ((MatrixObject*)m2); + + //coerced int or float for scalar multiplication + if(matW->flag > 1 || matW->flag > 2){ + + if(rowSizeV != rowSizeW && colSizeV != colSizeW) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "Matrix dimension error during scalar multiplication\n"); + + mat = PyMem_Malloc (matSizeV * sizeof(float)); + + for(x = 0; x < rowSizeV; x++){ + for(y = 0; y < colSizeV; y++){ + mat[((x * rowSizeV) + y)] = + matV->matrix[x][y] * matW->matrix[x][y]; + } + } + return newMatrixObject(mat, rowSizeV, colSizeV); + } + else if (matW->flag == 0 && matV->flag == 0){ //true matrix multiplication + if(colSizeV != rowSizeW){ + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "Matrix multiplication undefined...\n"); + } + + mat = PyMem_Malloc((rowSizeV * colSizeW) * sizeof(float)); + + for(x = 0; x < rowSizeV; x++){ + for(y = 0; y < colSizeW; y++){ + for(z = 0; z < colSizeV; z++){ + dot += (matV->matrix[x][z] * matW->matrix[z][y]); + } + mat[((x * rowSizeV) + y)] = dot; + dot = 0; + } + } + return newMatrixObject(mat, rowSizeV, colSizeW); + } + else + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "Error in matrix_mul...\n"); +} + +//coercion of unknown types to type MatrixObject for numeric protocols +int Matrix_coerce(PyObject **m1, PyObject **m2) +{ + long *tempI; + double *tempF; + float *mat; + int x, matSize; + + matSize = (((MatrixObject*)*m1)->rowSize) * (((MatrixObject*)*m1)->rowSize); + if (Matrix_CheckPyObject(*m1)) { + if (Matrix_CheckPyObject(*m2)) { //matrix & matrix + Py_INCREF(*m1); + Py_INCREF(*m2); + return 0; + }else{ + if(VectorObject_Check(*m2)){ //matrix & vector? + printf("use MatMultVec() for column vector multiplication\n"); + Py_INCREF(*m1); + return 0; + }else if(PyNumber_Check(*m2)){ //& scalar? + if(PyInt_Check(*m2)){ //it's a int + tempI = PyMem_Malloc(1*sizeof(long)); + *tempI = PyInt_AsLong(*m2); + mat = PyMem_Malloc (matSize * sizeof (float)); + for(x = 0; x < matSize; x++){ + mat[x] = (float)*tempI; + } + PyMem_Free(tempI); + *m2 = newMatrixObject(mat, (((MatrixObject*)*m1)->rowSize), + (((MatrixObject*)*m1)->colSize)); + ((MatrixObject*)*m2)->flag = 1; //int coercion + PyMem_Free(mat); + Py_INCREF(*m1); + return 0; + }else if(PyFloat_Check(*m2)){ //it's a float + tempF = PyMem_Malloc(1*sizeof(double)); + *tempF = PyFloat_AsDouble(*m2); + mat = PyMem_Malloc (matSize * sizeof (float)); + for(x = 0; x < matSize; x++){ + mat[x] = (float)*tempF; + } + PyMem_Free(tempF); + *m2 = newMatrixObject(mat, (((MatrixObject*)*m1)->rowSize), + (((MatrixObject*)*m1)->colSize)); + ((MatrixObject*)*m2)->flag = 2; //float coercion + PyMem_Free(mat); + Py_INCREF(*m1); + return 0; + } + } + //unknom2n type or numeric cast failure + printf("attempting matrix operation m2ith unsupported type...\n"); + Py_INCREF(*m1); + return 0; //operation m2ill type check + } + }else{ + //1st not Matrix + printf("numeric protocol failure...\n"); + return -1; //this should not occur - fail + } + return -1; +} + +//****************************************************************** +// Matrix definition +//****************************************************************** static PySequenceMethods Matrix_SeqMethods = { - (inquiry) 0, /*sq_length*/ - (binaryfunc) 0, /*sq_concat*/ - (intargfunc) 0, /*sq_repeat*/ - (intargfunc) Matrix_item, /*sq_item*/ - (intintargfunc) 0, /*sq_slice*/ - (intobjargproc) 0, /*sq_ass_item*/ - (intintobjargproc) 0, /*sq_ass_slice*/ + (inquiry) Matrix_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Matrix_item, /* sq_item */ + (intintargfunc) Matrix_slice, /* sq_slice */ + (intobjargproc) Matrix_ass_item, /* sq_ass_item */ + (intintobjargproc) Matrix_ass_slice, /* sq_ass_slice */ }; -PyTypeObject Matrix_Type = +static PyNumberMethods Matrix_NumMethods = +{ + (binaryfunc) Matrix_add, /* __add__ */ + (binaryfunc) Matrix_sub, /* __sub__ */ + (binaryfunc) Matrix_mul, /* __mul__ */ + (binaryfunc) 0, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) 0, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + (coercion) Matrix_coerce, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ +}; + +PyTypeObject matrix_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "Matrix", /*tp_name*/ sizeof(MatrixObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - /* methods */ (destructor) Matrix_dealloc, /*tp_dealloc*/ (printfunc) 0, /*tp_print*/ (getattrfunc) Matrix_getattr, /*tp_getattr*/ (setattrfunc) Matrix_setattr, /*tp_setattr*/ 0, /*tp_compare*/ (reprfunc) Matrix_repr, /*tp_repr*/ - 0, /*tp_as_number*/ + &Matrix_NumMethods, /*tp_as_number*/ &Matrix_SeqMethods, /*tp_as_sequence*/ }; -PyObject * newMatrixObject (float mat[][4]) +//****************************************************************** +//Function: newMatrixObject +//****************************************************************** +PyObject * newMatrixObject (float * mat, int rowSize, int colSize) { MatrixObject * self; + float * contigPtr; + int row, col, x; - self = PyObject_NEW (MatrixObject, &Matrix_Type); - if (mat) - { - self->mem = NULL; - self->mat = mat; - } - else - { - self->mem = PyMem_Malloc (4*4*sizeof (float)); - self->mat = self->mem; - } - self->rows[0] = newVectorObject ((float *)(self->mat[0]), 4); - self->rows[1] = newVectorObject ((float *)(self->mat[1]), 4); - self->rows[2] = newVectorObject ((float *)(self->mat[2]), 4); - self->rows[3] = newVectorObject ((float *)(self->mat[3]), 4); - if ((self->rows[0] == NULL) || - (self->rows[1] == NULL) || - (self->rows[2] == NULL) || - (self->rows[3] == NULL)) - { - return (EXPP_ReturnPyObjError (PyExc_RuntimeError, - "Something wrong with creating a matrix object")); + if (rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4) + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "row and column sizes must be between 2 and 4\n")); + + self = PyObject_NEW (MatrixObject, &matrix_Type); + + //generate contigous memory space + contigPtr = PyMem_Malloc(rowSize * colSize* sizeof(float)); + if(contigPtr == NULL){ + return (EXPP_ReturnPyObjError (PyExc_MemoryError, + "problem allocating array space\n\n")); + } + + //create pointer array + self->matrix = PyMem_Malloc(rowSize * sizeof(float*)); + if(self->matrix == NULL){ + return (EXPP_ReturnPyObjError (PyExc_MemoryError, + "problem allocating pointer space\n\n")); + } + + //pointer array points to contigous memory + for (x = 0; x < rowSize; x++){ + self->matrix[x] = contigPtr + (x * colSize); } + if(mat){ //if a float array passed + for (row = 0; row < rowSize; row++){ + for(col = 0; col < colSize; col++){ + self->matrix[row][col] = mat[(row * colSize) + col]; + } + } + }else{ //or if NULL passed + for (row = 0; row < rowSize; row++){ + for (col = 0; col < colSize; col++){ + self->matrix[row][col] = 0.0f; + } + } + } + + //set size vars of matrix + self->rowSize = rowSize; + self->colSize = colSize; + + //set coercion flag + self->flag = 0; + return ((PyObject *)self); } -void init_py_matrix (void) -{ - Matrix_Type.ob_type = &PyType_Type; -} + diff --git a/source/blender/python/api2_2x/matrix.h b/source/blender/python/api2_2x/matrix.h new file mode 100644 index 00000000000..b7370179a74 --- /dev/null +++ b/source/blender/python/api2_2x/matrix.h @@ -0,0 +1,77 @@ +/* + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_matrix_h +#define EXPP_matrix_h + +#include "Python.h" +#include "BLI_arithb.h" +#include "vector.h" +#include "gen_utils.h" +#include "Types.h" +#include "quat.h" +#include "euler.h" + +#define Matrix_CheckPyObject(v) ((v)->ob_type == &matrix_Type) + +/*****************************/ +/* Matrix Python Object */ +/*****************************/ +typedef float **ptRow; + +typedef struct _Matrix { + PyObject_VAR_HEAD + + ptRow matrix; + int rowSize; + int colSize; + int flag; + //0 - no coercion + //1 - coerced from int + //2 - coerced from float +} MatrixObject; + +/*****************************************************************************/ +/* Python API function prototypes. */ +/*****************************************************************************/ +PyObject *newMatrixObject(float * mat, int rowSize, int colSize); +PyObject *Matrix_Zero(MatrixObject *self); +PyObject *Matrix_Identity(MatrixObject *self); +PyObject *Matrix_Transpose(MatrixObject *self); +PyObject *Matrix_Determinant(MatrixObject *self); +PyObject *Matrix_Invert(MatrixObject *self); +PyObject *Matrix_TranslationPart(MatrixObject *self); +PyObject *Matrix_RotationPart(MatrixObject *self); +PyObject *Matrix_Resize4x4(MatrixObject *self); +PyObject *Matrix_toEuler(MatrixObject *self); +PyObject *Matrix_toQuat(MatrixObject *self); + +#endif /* EXPP_matrix_H */ diff --git a/source/blender/python/api2_2x/modules.h b/source/blender/python/api2_2x/modules.h index 899b368cdca..43a56f1379f 100644 --- a/source/blender/python/api2_2x/modules.h +++ b/source/blender/python/api2_2x/modules.h @@ -184,5 +184,7 @@ int Lattice_CheckPyObject (PyObject *pyobj); PyObject * Window_Init (void); PyObject * Draw_Init (void); PyObject * BGL_Init (void); +PyObject * Mathutils_Init (void); + #endif /* EXPP_modules_h */ diff --git a/source/blender/python/api2_2x/quat.c b/source/blender/python/api2_2x/quat.c new file mode 100644 index 00000000000..3d785570027 --- /dev/null +++ b/source/blender/python/api2_2x/quat.c @@ -0,0 +1,504 @@ +/* + * ***** 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. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "quat.h" + +//doc strings +char Quaternion_Identity_doc[] = +"() - set the quaternion to it's identity (1, vector)"; +char Quaternion_Negate_doc[] = +"() - set all values in the quaternion to their negative"; +char Quaternion_Conjugate_doc[] = +"() - set the quaternion to it's conjugate"; +char Quaternion_Inverse_doc[] = +"() - set the quaternion to it's inverse"; +char Quaternion_Normalize_doc[] = +"() - normalize the vector portion of the quaternion"; +char Quaternion_ToEuler_doc[] = +"() - return a euler rotation representing the quaternion"; +char Quaternion_ToMatrix_doc[] = +"() - return a rotation matrix representing the quaternion"; + +//methods table +struct PyMethodDef Quaternion_methods[] = { + {"identity",(PyCFunction)Quaternion_Identity, METH_NOARGS, + Quaternion_Identity_doc}, + {"negate",(PyCFunction)Quaternion_Negate, METH_NOARGS, + Quaternion_Negate_doc}, + {"conjugate",(PyCFunction)Quaternion_Conjugate, METH_NOARGS, + Quaternion_Conjugate_doc}, + {"inverse",(PyCFunction)Quaternion_Inverse, METH_NOARGS, + Quaternion_Inverse_doc}, + {"normalize",(PyCFunction)Quaternion_Normalize, METH_NOARGS, + Quaternion_Normalize_doc}, + {"toEuler",(PyCFunction)Quaternion_ToEuler, METH_NOARGS, + Quaternion_ToEuler_doc}, + {"toMatrix",(PyCFunction)Quaternion_ToMatrix, METH_NOARGS, + Quaternion_ToMatrix_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************/ +// Quaternion Python Object +/*****************************/ + +PyObject *Quaternion_ToEuler(QuaternionObject *self) +{ + float *eul; + int x; + + eul = PyMem_Malloc(3*sizeof(float)); + QuatToEul(self->quat, eul); + + for(x = 0; x < 3; x++){ + eul[x] *= (float)(180/Py_PI); + } + return (PyObject*)newEulerObject(eul); +} + +PyObject *Quaternion_ToMatrix(QuaternionObject *self) +{ + float *mat; + + mat = PyMem_Malloc(3*3*sizeof(float)); + QuatToMat3(self->quat, (float(*)[3])mat); + + return (PyObject*)newMatrixObject(mat, 3,3); +} + +//normalize the axis of rotation of [theta,vector] +PyObject *Quaternion_Normalize(QuaternionObject *self) +{ + NormalQuat(self->quat); + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Inverse(QuaternionObject *self) +{ + float mag = 0.0f; + int x; + + for(x = 1; x < 4; x++){ + self->quat[x] = -self->quat[x]; + } + for(x = 0; x < 4; x++){ + mag += (self->quat[x] * self->quat[x]); + } + mag = (float)sqrt(mag); + for(x = 0; x < 4; x++){ + self->quat[x] /= (mag * mag); + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Identity(QuaternionObject *self) +{ + self->quat[0] = 1.0; + self->quat[1] = 0.0; self->quat[2] = 0.0; self->quat[3] = 0.0; + + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Negate(QuaternionObject *self) +{ + int x; + + for(x = 0; x < 4; x++){ + self->quat[x] = -self->quat[x]; + } + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Conjugate(QuaternionObject *self) +{ + int x; + + for(x = 1; x < 4; x++){ + self->quat[x] = -self->quat[x]; + } + return EXPP_incr_ret(Py_None); +} + +static void Quaternion_dealloc(QuaternionObject *self) +{ + PyObject_DEL (self); +} + +static PyObject *Quaternion_getattr(QuaternionObject *self, char *name) +{ + double mag = 0.0f; + float *vec; + int x; + + if (ELEM4(name[0], 'w', 'x', 'y', 'z') && name[1]==0){ + return PyFloat_FromDouble(self->quat[name[0]-'w']); + } + if(strcmp(name,"magnitude") == 0){ + for(x = 0; x < 4; x++){ + mag += self->quat[x] * self->quat[x]; + } + mag = (float)sqrt(mag); + return PyFloat_FromDouble(mag); + } + if(strcmp(name,"angle") == 0){ + + mag = self->quat[0]; + mag = 2 * (acos(mag)); + mag *= (180/Py_PI); + return PyFloat_FromDouble(mag); + } + if(strcmp(name,"axis") == 0){ + + mag = (double)(self->quat[0] * (Py_PI/180)); + mag = 2 * (acos(mag)); + mag = sin(mag/2); + vec = PyMem_Malloc(3*sizeof(float)); + for(x = 0; x < 3; x++){ + vec[x] = (self->quat[x + 1]/((float)(mag))); + } + Normalise(vec); + return (PyObject*)newVectorObject(vec,3); + } + return Py_FindMethod(Quaternion_methods, (PyObject*)self, name); +} + +static int Quaternion_setattr(QuaternionObject *self, char *name, PyObject *v) +{ + float val; + + if(!PyFloat_Check(v) && !PyInt_Check(v)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + if (!PyArg_Parse(v, "f", &val)) + return EXPP_ReturnIntError(PyExc_TypeError, "unable to parse float argument\n"); + } + if (ELEM4(name[0], 'w', 'x', 'y', 'z') && name[1]==0){ + self->quat[name[0]-'w']= val; + }else return -1; + + return 0; +} + +/* Quaternions Sequence methods */ +static PyObject *Quaternion_item(QuaternionObject *self, int i) +{ + if (i < 0 || i >= 4) + return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); + + return Py_BuildValue("f", self->quat[i]); +} + +static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end) +{ + PyObject *list; + int count; + + if (begin < 0) begin= 0; + if (end > 4) end= 4; + if (begin > end) begin= end; + + list= PyList_New(end-begin); + + for (count = begin; count < end; count++){ + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->quat[count])); + } + return list; +} + +static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob) +{ + if (i < 0 || i >= 4) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + if (!PyNumber_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "Quaternion member must be a number\n"); + + if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + self->quat[i]= (float)PyFloat_AsDouble(ob); + } + return 0; +} + +static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq) +{ + int count, z; + + if (begin < 0) begin= 0; + if (end > 4) end= 4; + if (begin > end) begin= end; + + if (!PySequence_Check(seq)) + return EXPP_ReturnIntError(PyExc_TypeError, + "illegal argument type for built-in operation\n"); + if (PySequence_Length(seq) != (end - begin)) + return EXPP_ReturnIntError(PyExc_TypeError, + "size mismatch in slice assignment\n"); + + z = 0; + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, z); z++; + + if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ + Py_DECREF(ob); + return -1; + }else{ + if (!PyArg_Parse(ob, "f", &self->quat[count])) { + Py_DECREF(ob); + return -1; + } + } + } + return 0; +} + +static PyObject *Quaternion_repr (QuaternionObject *self) +{ + int i, maxindex = 4 - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString ("["); + + for (i = 0; i < maxindex; i++) { + sprintf(ftoa, "%.4f, ", self->quat[i]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + } + + sprintf(ftoa, "%.4f]\n", self->quat[maxindex]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + + if (str1) return str1; + +error: + Py_XDECREF (str1); + Py_XDECREF (str2); + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyString!\n"); +} + + +PyObject * Quaternion_add(PyObject *q1, PyObject *q2) +{ + float * quat; + int x; + + if((!QuaternionObject_Check(q1)) || (!QuaternionObject_Check(q2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((QuaternionObject*)q1)->flag > 0 || ((QuaternionObject*)q2)->flag > 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot add a scalar and a quat\n"); + + quat = PyMem_Malloc (4*sizeof(float)); + for(x = 0; x < 4; x++){ + quat[x] = (((QuaternionObject*)q1)->quat[x]) + (((QuaternionObject*)q2)->quat[x]); + } + + return (PyObject*)newQuaternionObject(quat); +} + +PyObject * Quaternion_sub(PyObject *q1, PyObject *q2) +{ + float * quat; + int x; + + if((!QuaternionObject_Check(q1)) || (!QuaternionObject_Check(q2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((QuaternionObject*)q1)->flag > 0 || ((QuaternionObject*)q2)->flag > 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot subtract a scalar and a quat\n"); + + quat = PyMem_Malloc (4*sizeof(float)); + for(x = 0; x < 4; x++){ + quat[x] = (((QuaternionObject*)q1)->quat[x]) - (((QuaternionObject*)q2)->quat[x]); + } + return (PyObject*)newQuaternionObject(quat); +} + +PyObject * Quaternion_mul(PyObject *q1, PyObject * q2) +{ + float * quat; + int x; + + if((!QuaternionObject_Check(q1)) || (!QuaternionObject_Check(q2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((QuaternionObject*)q1)->flag == 0 && ((QuaternionObject*)q2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "please use the dot or cross product to multiply quaternions\n"); + + quat = PyMem_Malloc (4*sizeof(float)); + //scalar mult by quat + for(x = 0; x < 4; x++){ + quat[x] = ((QuaternionObject*)q1)->quat[x] * ((QuaternionObject*)q2)->quat[x]; + } + return (PyObject*)newQuaternionObject(quat); +} + +//coercion of unknown types to type QuaternionObject for numeric protocols +int Quaternion_coerce(PyObject **q1, PyObject **q2) +{ + long *tempI; + double *tempF; + float *quat; + int x; + + if (QuaternionObject_Check(*q1)) { + if (QuaternionObject_Check(*q2)) { //two Quaternions + Py_INCREF(*q1); + Py_INCREF(*q2); + return 0; + }else{ + if(PyNumber_Check(*q2)){ + if(PyInt_Check(*q2)){ //cast scalar to Quaternion + tempI = PyMem_Malloc(1*sizeof(long)); + *tempI = PyInt_AsLong(*q2); + quat = PyMem_Malloc (4*sizeof (float)); + for(x = 0; x < 4; x++){ + quat[x] = (float)*tempI; + } + PyMem_Free(tempI); + *q2 = newQuaternionObject(quat); + ((QuaternionObject*)*q2)->flag = 1; //int coercion + Py_INCREF(*q1); + return 0; + }else if(PyFloat_Check(*q2)){ //cast scalar to Quaternion + tempF = PyMem_Malloc(1*sizeof(double)); + *tempF = PyFloat_AsDouble(*q2); + quat = PyMem_Malloc (4*sizeof (float)); + for(x = 0; x < 4; x++){ + quat[x] = (float)*tempF; + } + PyMem_Free(tempF); + *q2 = newQuaternionObject(quat); + ((QuaternionObject*)*q2)->flag = 2; //float coercion + Py_INCREF(*q1); + return 0; + } + } + //unknown type or numeric cast failure + printf("attempting quaternion operation with unsupported type...\n"); + Py_INCREF(*q1); + return 0; //operation will type check + } + }else{ + printf("numeric protocol failure...\n"); + return -1; //this should not occur - fail + } + return -1; +} + +static PySequenceMethods Quaternion_SeqMethods = +{ + (inquiry) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Quaternion_item, /* sq_item */ + (intintargfunc) Quaternion_slice, /* sq_slice */ + (intobjargproc) Quaternion_ass_item, /* sq_ass_item */ + (intintobjargproc) Quaternion_ass_slice, /* sq_ass_slice */ +}; + +static PyNumberMethods Quaternion_NumMethods = +{ + (binaryfunc) Quaternion_add, /* __add__ */ + (binaryfunc) Quaternion_sub, /* __sub__ */ + (binaryfunc) Quaternion_mul, /* __mul__ */ + (binaryfunc) 0, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) 0, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + (coercion) Quaternion_coerce, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ + +}; + +PyTypeObject quaternion_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "quaternion", /*tp_name*/ + sizeof(QuaternionObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor) Quaternion_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) Quaternion_getattr, /*tp_getattr*/ + (setattrfunc) Quaternion_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Quaternion_repr, /*tp_repr*/ + &Quaternion_NumMethods, /*tp_as_number*/ + &Quaternion_SeqMethods, /*tp_as_sequence*/ +}; + +PyObject *newQuaternionObject(float *quat) +{ + QuaternionObject *self; + int x; + + quaternion_Type.ob_type = &PyType_Type; + + self = PyObject_NEW(QuaternionObject, &quaternion_Type); + + if(!quat){ + self->quat = PyMem_Malloc (4 *sizeof (float)); + for(x = 0; x < 4; x++){ + self->quat[x] = 0.0f; + } + self->quat[3] = 1.0f; + }else{ + self->quat = quat; + } + self->flag = 0; + + return (PyObject*) self; +} + diff --git a/source/blender/python/api2_2x/quat.h b/source/blender/python/api2_2x/quat.h new file mode 100644 index 00000000000..586c8beba3e --- /dev/null +++ b/source/blender/python/api2_2x/quat.h @@ -0,0 +1,74 @@ +/* + * + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * + */ + +#ifndef EXPP_quat_h +#define EXPP_quat_h + +#include "Python.h" +#include "gen_utils.h" +#include "Types.h" +#include <BLI_arithb.h> +#include "euler.h" +#include "matrix.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/*****************************/ +// Quaternion Python Object +/*****************************/ + +#define QuaternionObject_Check(v) ((v)->ob_type == &quaternion_Type) + +typedef struct { + PyObject_VAR_HEAD + float * quat; + int flag; + //0 - no coercion + //1 - coerced from int + //2 - coerced from float +} QuaternionObject; + + +//prototypes +PyObject *newQuaternionObject(float *quat); +PyObject *Quaternion_Identity(QuaternionObject *self); +PyObject *Quaternion_Negate(QuaternionObject *self); +PyObject *Quaternion_Conjugate(QuaternionObject *self); +PyObject *Quaternion_Inverse(QuaternionObject *self); +PyObject *Quaternion_Normalize(QuaternionObject *self); +PyObject *Quaternion_ToEuler(QuaternionObject *self); +PyObject *Quaternion_ToMatrix(QuaternionObject *self); + +#endif /* EXPP_quat_h */ + diff --git a/source/blender/python/api2_2x/vector.c b/source/blender/python/api2_2x/vector.c index d08775aa6a7..efb13787204 100644 --- a/source/blender/python/api2_2x/vector.c +++ b/source/blender/python/api2_2x/vector.c @@ -1,5 +1,4 @@ -/* - * + /* * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -23,19 +22,162 @@ * All rights reserved. * * - * Contributor(s): Willian P. Germano + * Contributor(s): Willian P. Germano & Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -/* This file is the old bpython opy_vector.c with minor modifications */ - #include "vector.h" +//doc strings +char Vector_Zero_doc[] = +"() - set all values in the vector to 0"; +char Vector_Normalize_doc[] = +"() - normalize the vector"; +char Vector_Negate_doc[] = +"() - changes vector to it's additive inverse"; +char Vector_Resize2D_doc[] = +"() - resize a vector to [x,y]"; +char Vector_Resize3D_doc[] = +"() - resize a vector to [x,y,z]"; +char Vector_Resize4D_doc[] = +"() - resize a vector to [x,y,z,w]"; + +//method table +struct PyMethodDef Vector_methods[] = { + {"zero",(PyCFunction)Vector_Zero, METH_NOARGS, + Vector_Zero_doc}, + {"normalize",(PyCFunction)Vector_Normalize, METH_NOARGS, + Vector_Normalize_doc}, + {"negate",(PyCFunction)Vector_Negate, METH_NOARGS, + Vector_Negate_doc}, + {"resize2D",(PyCFunction)Vector_Resize2D, METH_NOARGS, + Vector_Resize2D_doc}, + {"resize3D",(PyCFunction)Vector_Resize3D, METH_NOARGS, + Vector_Resize2D_doc}, + {"resize4D",(PyCFunction)Vector_Resize4D, METH_NOARGS, + Vector_Resize2D_doc}, + {NULL, NULL, 0, NULL} +}; + /*****************************/ -/* Vector Python Object */ +// Vector Python Object /*****************************/ -#define VectorObject_Check(v) ((v)->ob_type == &vector_Type) + +//object methods +PyObject *Vector_Zero(VectorObject *self) +{ + int x; + for(x = 0; x < self->size; x++){ + self->vec[x] = 0.0f; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Normalize(VectorObject *self) +{ + float norm; + int x; + + norm = 0.0f; + for(x = 0; x < self->size; x++){ + norm += self->vec[x] * self->vec[x]; + } + norm = (float)sqrt(norm); + for(x = 0; x < self->size; x++){ + self->vec[x] /= norm; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Negate(VectorObject *self) +{ + int x; + for(x = 0; x < self->size; x++){ + self->vec[x] = -(self->vec[x]); + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Resize2D(VectorObject *self) +{ + float x, y; + + if(self->size == 4 || self->size == 3){ + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(2*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->size = 2; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Resize3D(VectorObject *self) +{ + float x, y, z; + + if(self->size == 2){ + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(3*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = 0.0f; + self->size = 3; + } + else if (self->size == 4){ + x = self->vec[0]; + y = self->vec[1]; + z = self->vec[2]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(3*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = z; + self->size = 3; + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Vector_Resize4D(VectorObject *self) +{ + float x, y, z; + + if(self->size == 2){ + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(4*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = 0.0f; + self->vec[3] = 1.0f; + self->size = 4; + } + else if (self->size == 3){ + x = self->vec[0]; + y = self->vec[1]; + z = self->vec[2]; + PyMem_Free(self->vec); + self->vec = PyMem_Malloc(4*sizeof (float)); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = z; + self->vec[3] = 1.0f; + self->size = 4; + } + + return EXPP_incr_ret(Py_None); +} static void Vector_dealloc(VectorObject *self) { @@ -44,144 +186,374 @@ static void Vector_dealloc(VectorObject *self) static PyObject *Vector_getattr(VectorObject *self, char *name) { - if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) - return PyFloat_FromDouble(self->vec[ name[0]-'x' ]); - - return EXPP_ReturnPyObjError(PyExc_AttributeError, "attribute not found"); + if (self->size==4 && ELEM4(name[0], 'x', 'y', 'z', 'w') && name[1]==0){ + if ((name[0]) == ('w')){ + return PyFloat_FromDouble(self->vec[3]); + }else{ + return PyFloat_FromDouble(self->vec[name[0]-'x']); + } + } + else if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) + return PyFloat_FromDouble(self->vec[name[0]-'x']); + else if (self->size==2 && ELEM(name[0], 'x', 'y') && name[1]==0) + return PyFloat_FromDouble(self->vec[name[0]-'x']); + + if ((strcmp(name,"length") == 0)){ + if(self->size == 4){ + return PyFloat_FromDouble(sqrt(self->vec[0] * self->vec[0] + + self->vec[1] * self->vec[1] + + self->vec[2] * self->vec[2] + + self->vec[3] * self->vec[3])); + } + else if(self->size == 3){ + return PyFloat_FromDouble(sqrt(self->vec[0] * self->vec[0] + + self->vec[1] * self->vec[1] + + self->vec[2] * self->vec[2])); + }else if (self->size == 2){ + return PyFloat_FromDouble(sqrt(self->vec[0] * self->vec[0] + + self->vec[1] * self->vec[1])); + }else EXPP_ReturnPyObjError(PyExc_AttributeError, + "can only return the length of a 2D ,3D or 4D vector\n"); + } + + return Py_FindMethod(Vector_methods, (PyObject*)self, name); } static int Vector_setattr(VectorObject *self, char *name, PyObject *v) { - float val; - - if (!PyArg_Parse(v, "f", &val)) - return EXPP_ReturnIntError(PyExc_TypeError, - "expected float argument"); - - if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) - self->vec[ name[0]-'x' ]= val; - else - return -1; - - return 0; + float val; + int valTemp; + + if(!PyFloat_Check(v)){ + if(!PyInt_Check(v)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + if (!PyArg_Parse(v, "i", &valTemp)) + return EXPP_ReturnIntError(PyExc_TypeError, "unable to parse int argument\n"); + val = (float)valTemp; + } + }else{ + if (!PyArg_Parse(v, "f", &val)) + return EXPP_ReturnIntError(PyExc_TypeError, "unable to parse float argument\n"); + } + if (self->size==4 && ELEM4(name[0], 'x', 'y', 'z', 'w') && name[1]==0){ + if ((name[0]) == ('w')){ + self->vec[3]= val; + }else{ + self->vec[name[0]-'x']= val; + } + } + else if (self->size==3 && ELEM3(name[0], 'x', 'y', 'z') && name[1]==0) + self->vec[name[0]-'x']= val; + else if (self->size==2 && ELEM(name[0], 'x', 'y') && name[1]==0) + self->vec[name[0]-'x']= val; + else return -1; + + return 0; } /* Vectors Sequence methods */ - static int Vector_len(VectorObject *self) { - return self->size; + return self->size; } static PyObject *Vector_item(VectorObject *self, int i) { - if (i < 0 || i >= self->size) - return EXPP_ReturnPyObjError (PyExc_IndexError, - "array index out of range"); + if (i < 0 || i >= self->size) + return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); + + return Py_BuildValue("f", self->vec[i]); - return Py_BuildValue("f", self->vec[i]); } static PyObject *Vector_slice(VectorObject *self, int begin, int end) { - PyObject *list; - int count; + PyObject *list; + int count; - if (begin < 0) begin= 0; - if (end > self->size) end= self->size; - if (begin > end) begin= end; + if (begin < 0) begin= 0; + if (end > self->size) end= self->size; + if (begin > end) begin= end; - list= PyList_New(end-begin); + list= PyList_New(end-begin); - for (count = begin; count < end; count++) - PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->vec[count])); + for (count = begin; count < end; count++){ + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->vec[count])); + } - return list; + return list; } static int Vector_ass_item(VectorObject *self, int i, PyObject *ob) { - if (i < 0 || i >= self->size) - return EXPP_ReturnIntError(PyExc_IndexError, - "array assignment index out of range"); + if (i < 0 || i >= self->size) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + if (!PyInt_Check(ob) && !PyFloat_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "vector member must be a number\n"); - if (!PyNumber_Check(ob)) - return EXPP_ReturnIntError(PyExc_IndexError, - "vector member must be a number"); + self->vec[i]= (float)PyFloat_AsDouble(ob); - self->vec[i]= PyFloat_AsDouble(ob); - - return 0; + return 0; } static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq) { - int count; - - if (begin < 0) begin= 0; - if (end > self->size) end= self->size; - if (begin > end) begin= end; - - if (!PySequence_Check(seq)) - return EXPP_ReturnIntError(PyExc_TypeError, - "illegal argument type for built-in operation"); - - if (PySequence_Length(seq) != (end - begin)) - return EXPP_ReturnIntError(PyExc_TypeError, - "size mismatch in slice assignment"); - - for (count = begin; count < end; count++) { - PyObject *ob = PySequence_GetItem(seq, count); - - if (!PyArg_Parse(ob, "f", &self->vec[count])) { - Py_DECREF(ob); - return -1; - } - - Py_DECREF(ob); - } + int count, z; + + if (begin < 0) begin= 0; + if (end > self->size) end= self->size; + if (begin > end) begin= end; + + if (!PySequence_Check(seq)) + return EXPP_ReturnIntError(PyExc_TypeError, + "illegal argument type for built-in operation\n"); + if (PySequence_Length(seq) != (end - begin)) + return EXPP_ReturnIntError(PyExc_TypeError, + "size mismatch in slice assignment\n"); + + z = 0; + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, z); z++; + if (!PyInt_Check(ob) && !PyFloat_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "list member must be a number\n"); + + if (!PyArg_Parse(ob, "f", &self->vec[count])){ + Py_DECREF(ob); + return -1; + } + } return 0; } static PyObject *Vector_repr (VectorObject *self) { - int i, maxindex = self->size - 1; - char ftoa[24]; - PyObject *str1, *str2; + int i, maxindex = self->size - 1; + char ftoa[24]; + PyObject *str1, *str2; - str1 = PyString_FromString ("["); + str1 = PyString_FromString ("["); - for (i = 0; i < maxindex; i++) { - sprintf(ftoa, "%.3f, ", self->vec[i]); - str2 = PyString_FromString (ftoa); - if (!str1 || !str2) goto error; /* my first goto : ) */ - PyString_ConcatAndDel (&str1, str2); - } + for (i = 0; i < maxindex; i++) { + sprintf(ftoa, "%.4f, ", self->vec[i]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + } - sprintf(ftoa, "%.3f]\n", self->vec[maxindex]); - str2 = PyString_FromString (ftoa); - if (!str1 || !str2) goto error; /* uh-oh, became a habit */ - PyString_ConcatAndDel (&str1, str2); + sprintf(ftoa, "%.4f]\n", self->vec[maxindex]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); - if (str1) return str1; + if (str1) return str1; error: - Py_XDECREF (str1); - Py_XDECREF (str2); - return EXPP_ReturnPyObjError (PyExc_MemoryError, - "couldn't create PyString!"); + Py_XDECREF (str1); + Py_XDECREF (str2); + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyString!\n"); +} + + +PyObject * Vector_add(PyObject *v1, PyObject *v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag != 0 || ((VectorObject*)v2)->flag != 0) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "cannot add a scalar to a vector\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vectors must have the same dimensions for this operation\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof (float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] + ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); +} + +PyObject * Vector_sub(PyObject *v1, PyObject *v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag != 0 || ((VectorObject*)v2)->flag != 0) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "cannot subtract a scalar from a vector\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vectors must have the same dimensions for this operation\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof (float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] - ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); +} + +PyObject * Vector_mul(PyObject *v1, PyObject * v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag == 0 && ((VectorObject*)v2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "please use the dot product or the cross product to multiply vectors\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vector dimension error during Vector_mul\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof(float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] * ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); +} + +PyObject * Vector_div(PyObject *v1, PyObject * v2) +{ + float * vec; + int x; + + if((!VectorObject_Check(v1)) || (!VectorObject_Check(v2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((VectorObject*)v1)->flag == 0 && ((VectorObject*)v2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot divide two vectors\n"); + if(((VectorObject*)v1)->flag != 0 && ((VectorObject*)v2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "cannot divide a scalar by a vector\n"); + if(((VectorObject*)v1)->size != ((VectorObject*)v2)->size) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "vector dimension error during Vector_mul\n"); + + vec = PyMem_Malloc ((((VectorObject*)v1)->size)*sizeof(float)); + + for(x = 0; x < ((VectorObject*)v1)->size; x++){ + vec[x] = ((VectorObject*)v1)->vec[x] / ((VectorObject*)v2)->vec[x]; + } + + return (PyObject*)newVectorObject(vec, (((VectorObject*)v1)->size)); } +//coercion of unknown types to type VectorObject for numeric protocols +int Vector_coerce(PyObject **v1, PyObject **v2) +{ + long *tempI; + double *tempF; + float *vec; + int x; + + if (VectorObject_Check(*v1)) { + if (VectorObject_Check(*v2)) { //two vectors + Py_INCREF(*v1); + Py_INCREF(*v2); + return 0; + }else{ + if(Matrix_CheckPyObject(*v2)){ + printf("vector/matrix numeric protocols unsupported...\n"); + Py_INCREF(*v1); + return 0; //operation will type check + }else if(PyNumber_Check(*v2)){ + if(PyInt_Check(*v2)){ //cast scalar to vector + tempI = PyMem_Malloc(1*sizeof(long)); + *tempI = PyInt_AsLong(*v2); + vec = PyMem_Malloc ((((VectorObject*)*v1)->size)*sizeof (float)); + for(x = 0; x < (((VectorObject*)*v1)->size); x++){ + vec[x] = (float)*tempI; + } + PyMem_Free(tempI); + *v2 = newVectorObject(vec, (((VectorObject*)*v1)->size)); + ((VectorObject*)*v2)->flag = 1; //int coercion + Py_INCREF(*v1); + return 0; + }else if(PyFloat_Check(*v2)){ //cast scalar to vector + tempF = PyMem_Malloc(1*sizeof(double)); + *tempF = PyFloat_AsDouble(*v2); + vec = PyMem_Malloc ((((VectorObject*)*v1)->size)*sizeof (float)); + for(x = 0; x < (((VectorObject*)*v1)->size); x++){ + vec[x] = (float)*tempF; + } + PyMem_Free(tempF); + *v2 = newVectorObject(vec, (((VectorObject*)*v1)->size)); + ((VectorObject*)*v2)->flag = 2; //float coercion + Py_INCREF(*v1); + return 0; + } + } + //unknown type or numeric cast failure + printf("attempting vector operation with unsupported type...\n"); + Py_INCREF(*v1); + return 0; //operation will type check + } + }else{ + printf("numeric protocol failure...\n"); + return -1; //this should not occur - fail + } + return -1; +} + + static PySequenceMethods Vector_SeqMethods = { - (inquiry) Vector_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (intargfunc) 0, /* sq_repeat */ - (intargfunc) Vector_item, /* sq_item */ - (intintargfunc) Vector_slice, /* sq_slice */ - (intobjargproc) Vector_ass_item, /* sq_ass_item */ - (intintobjargproc) Vector_ass_slice, /* sq_ass_slice */ + (inquiry) Vector_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Vector_item, /* sq_item */ + (intintargfunc) Vector_slice, /* sq_slice */ + (intobjargproc) Vector_ass_item, /* sq_ass_item */ + (intintobjargproc) Vector_ass_slice, /* sq_ass_slice */ +}; + +static PyNumberMethods Vector_NumMethods = +{ + (binaryfunc) Vector_add, /* __add__ */ + (binaryfunc) Vector_sub, /* __sub__ */ + (binaryfunc) Vector_mul, /* __mul__ */ + (binaryfunc) Vector_div, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) 0, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + (coercion) Vector_coerce, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ + }; PyTypeObject vector_Type = @@ -191,27 +563,38 @@ PyTypeObject vector_Type = "vector", /*tp_name*/ sizeof(VectorObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - /* methods */ (destructor) Vector_dealloc, /*tp_dealloc*/ (printfunc) 0, /*tp_print*/ (getattrfunc) Vector_getattr, /*tp_getattr*/ (setattrfunc) Vector_setattr, /*tp_setattr*/ 0, /*tp_compare*/ (reprfunc) Vector_repr, /*tp_repr*/ - 0, /*tp_as_number*/ + &Vector_NumMethods, /*tp_as_number*/ &Vector_SeqMethods, /*tp_as_sequence*/ }; PyObject *newVectorObject(float *vec, int size) { VectorObject *self; + int x; vector_Type.ob_type = &PyType_Type; self = PyObject_NEW(VectorObject, &vector_Type); - self->vec = vec; + if(!vec){ + self->vec = PyMem_Malloc (size *sizeof (float)); + for(x = 0; x < size; x++){ + self->vec[x] = 0.0f; + } + if(size == 4) self->vec[3] = 1.0f; + }else{ + self->vec = vec; + } + self->size = size; + self->flag = 0; return (PyObject*) self; } + diff --git a/source/blender/python/api2_2x/vector.h b/source/blender/python/api2_2x/vector.h index 2e0250c3a07..f8ad164543b 100644 --- a/source/blender/python/api2_2x/vector.h +++ b/source/blender/python/api2_2x/vector.h @@ -1,7 +1,3 @@ - - -/* Matrix and vector objects in Python */ - /* $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** @@ -28,7 +24,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): Willian P. Germano + * Contributor(s): Willian P. Germano & Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** * @@ -38,42 +34,39 @@ #define EXPP_vector_h #include "Python.h" - -#include "BKE_utildefines.h" - #include "gen_utils.h" -#include "vector.h" +#include "Types.h" +#include "matrix.h" +#include "BKE_utildefines.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif /*****************************/ -/* Matrix Python Object */ +// Vector Python Object /*****************************/ -/* temporar hack for typecasts */ -typedef float (*Matrix4Ptr)[4]; +#define VectorObject_Check(v) ((v)->ob_type == &vector_Type) typedef struct { PyObject_VAR_HEAD - float *vec; + float * vec; int size; - + int flag; + //0 - no coercion + //1 - coerced from int + //2 - coerced from float } VectorObject; -typedef struct { - PyObject_VAR_HEAD - PyObject *rows[4]; - Matrix4Ptr mat; - Matrix4Ptr mem; -} MatrixObject; - - -/* PROTOS */ - +//prototypes PyObject *newVectorObject(float *vec, int size); -PyObject *newMatrixObject(float mat[][4]); -void init_py_matrix(void); +PyObject *Vector_Zero(VectorObject *self); +PyObject *Vector_Normalize(VectorObject *self); +PyObject *Vector_Negate(VectorObject *self); +PyObject *Vector_Resize2D(VectorObject *self); +PyObject *Vector_Resize3D(VectorObject *self); +PyObject *Vector_Resize4D(VectorObject *self); #endif /* EXPP_vector_h */ + |