diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-01-25 12:44:04 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-01-25 12:44:04 +0300 |
commit | 0a0f4c9d81cfa2a4b4a9999e1dc976bc417d7d54 (patch) | |
tree | 367f259b695955a514530d125ab495344724eafb /source/blender/python/generic/Mathutils.c | |
parent | eed13d859b67185996569178ede9241a5695f215 (diff) |
Mathutils refactor & include in sphinx generated docs, (TODO, include getset'ers in docs)
- Mathutils.MidpointVecs --> vector.lerp(other, fac)
- Mathutils.AngleBetweenVecs --> vector.angle(other)
- Mathutils.ProjectVecs --> vector.project(other)
- Mathutils.DifferenceQuats --> quat.difference(other)
- Mathutils.Slerp --> quat.slerp(other, fac)
- Mathutils.Rand: removed, use pythons random module
- Mathutils.RotationMatrix(angle, size, axis_flag, axis) --> Mathutils.RotationMatrix(angle, size, axis); merge axis & axis_flag args
- Matrix.scalePart --> Matrix.scale_part
- Matrix.translationPart --> Matrix.translation_part
- Matrix.rotationPart --> Matrix.rotation_part
- toMatrix --> to_matrix
- toEuler --> to_euler
- toQuat --> to_quat
- Vector.toTrackQuat --> Vector.to_track_quat
Diffstat (limited to 'source/blender/python/generic/Mathutils.c')
-rw-r--r-- | source/blender/python/generic/Mathutils.c | 842 |
1 files changed, 174 insertions, 668 deletions
diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c index b44d6450145..2e4b6dbb490 100644 --- a/source/blender/python/generic/Mathutils.c +++ b/source/blender/python/generic/Mathutils.c @@ -27,114 +27,34 @@ * ***** END GPL LICENSE BLOCK ***** */ +/* Note: Changes to Mathutils since 2.4x + * use radians rather then degrees + * - Mathutils.MidpointVecs --> vector.lerp(other, fac) + * - Mathutils.AngleBetweenVecs --> vector.angle(other) + * - Mathutils.ProjectVecs --> vector.project(other) + * - Mathutils.DifferenceQuats --> quat.difference(other) + * - Mathutils.Slerp --> quat.slerp(other, fac) + * - Mathutils.Rand: removed, use pythons random module + * - Mathutils.RotationMatrix(angle, size, axis_flag, axis) --> Mathutils.RotationMatrix(angle, size, axis); merge axis & axis_flag args + * - Matrix.scalePart --> Matrix.scale_part + * - Matrix.translationPart --> Matrix.translation_part + * - Matrix.rotationPart --> Matrix.rotation_part + * - toMatrix --> to_matrix + * - toEuler --> to_euler + * - toQuat --> to_quat + * - Vector.toTrackQuat --> Vector.to_track_quat + * + * Moved to Geometry module: Intersect, TriangleArea, TriangleNormal, QuadNormal, LineIntersect + */ + #include "Mathutils.h" #include "BLI_math.h" #include "PIL_time.h" -#include "BLI_rand.h" #include "BKE_utildefines.h" //-------------------------DOC STRINGS --------------------------- -static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n"; -static char M_Mathutils_Rand_doc[] = "() - return a random number"; -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_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_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector"; -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_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise"; -static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined"; -static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined"; -static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined"; -static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other"; -//-----------------------METHOD DEFINITIONS ---------------------- - -static PyObject *M_Mathutils_Rand(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_ProjectVecs(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value); -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_DifferenceQuats(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ); - -struct PyMethodDef M_Mathutils_methods[] = { - {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc}, - {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc}, - {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc}, - {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_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_O, M_Mathutils_TranslationMatrix_doc}, - {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc}, - {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc}, - {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc}, - {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc}, - {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc}, - {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc}, - {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc}, - {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc}, - {NULL, NULL, 0, NULL} -}; - -/*----------------------------MODULE INIT-------------------------*/ -/* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */ - -static struct PyModuleDef M_Mathutils_module_def = { - PyModuleDef_HEAD_INIT, - "Mathutils", /* m_name */ - M_Mathutils_doc, /* m_doc */ - 0, /* m_size */ - M_Mathutils_methods, /* m_methods */ - 0, /* m_reload */ - 0, /* m_traverse */ - 0, /* m_clear */ - 0, /* m_free */ -}; - -PyObject *Mathutils_Init(void) -{ - PyObject *submodule; - - //seed the generator for the rand function - BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF)); - - if( PyType_Ready( &vector_Type ) < 0 ) - return NULL; - if( PyType_Ready( &matrix_Type ) < 0 ) - return NULL; - if( PyType_Ready( &euler_Type ) < 0 ) - return NULL; - if( PyType_Ready( &quaternion_Type ) < 0 ) - return NULL; - - submodule = PyModule_Create(&M_Mathutils_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule); - - /* each type has its own new() function */ - PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type ); - PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type ); - PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type ); - PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type ); - - mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb); - - return (submodule); -} +static char M_Mathutils_doc[] = "This module provides access to matrices, eulers, quaternions and vectors."; //-----------------------------METHODS---------------------------- //-----------------quat_rotation (internal)----------- @@ -204,164 +124,49 @@ PyObject *quat_rotation(PyObject *arg1, PyObject *arg2) } -//----------------------------------Mathutils.Rand() -------------------- -//returns a random number between a high and low value -static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args) -{ - float high, low, range; - double drand; - //initializers - high = 1.0; - low = 0.0; - - if(!PyArg_ParseTuple(args, "|ff", &low, &high)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Rand(): expected nothing or optional (float, float)\n"); - return NULL; - } - - if((high < low) || (high < 0 && low > 0)) { - PyErr_SetString(PyExc_ValueError, "Mathutils.Rand(): high value should be larger than low value\n"); - return NULL; - } - //get the random number 0 - 1 - drand = BLI_drand(); - - //set it to range - range = high - low; - drand = drand * range; - drand = drand + low; - - return PyFloat_FromDouble(drand); -} -//----------------------------------VECTOR FUNCTIONS--------------------- -//----------------------------------Mathutils.AngleBetweenVecs() --------- -//calculates the angle between 2 vectors -static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f; - int x, size; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - goto AttributeError1; //not vectors - if(vec1->size != vec2->size) - goto AttributeError1; //bad sizes - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - //since size is the same.... - size = vec1->size; - - for(x = 0; x < size; x++) { - test_v1 += vec1->vec[x] * vec1->vec[x]; - test_v2 += vec2->vec[x] * vec2->vec[x]; - } - if (!test_v1 || !test_v2){ - goto AttributeError2; //zero-length vector - } - - //dot product - for(x = 0; x < size; x++) { - dot += vec1->vec[x] * vec2->vec[x]; - } - dot /= (sqrt(test_v1) * sqrt(test_v2)); - - angleRads = (double)saacos(dot); - -#ifdef USE_MATHUTILS_DEG - return PyFloat_FromDouble(angleRads * (180/ Py_PI)); -#else - return PyFloat_FromDouble(angleRads); -#endif -AttributeError1: - PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n"); - return NULL; - -AttributeError2: - PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n"); - return NULL; -} -//----------------------------------Mathutils.MidpointVecs() ------------- -//calculates the midpoint between 2 vectors -static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - float vec[4]; - int x; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - for(x = 0; x < vec1->size; x++) { - vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]); - } - return newVectorObject(vec, vec1->size, Py_NEW, NULL); -} -//----------------------------------Mathutils.ProjectVecs() ------------- -//projects vector 1 onto vector 2 -static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - float vec[4]; - double dot = 0.0f, dot2 = 0.0f; - int x, size; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - - //since they are the same size... - size = vec1->size; - - //get dot products - for(x = 0; x < size; x++) { - dot += vec1->vec[x] * vec2->vec[x]; - dot2 += vec2->vec[x] * vec2->vec[x]; - } - //projection - dot /= dot2; - for(x = 0; x < size; x++) { - vec[x] = (float)(dot * vec2->vec[x]); - } - return newVectorObject(vec, size, Py_NEW, NULL); -} //----------------------------------MATRIX FUNCTIONS-------------------- //----------------------------------Mathutils.RotationMatrix() ---------- //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates a rotation matrix +static char M_Mathutils_RotationMatrix_doc[] = +".. function:: RotationMatrix(angle, size, axis)\n" +"\n" +" Create a matrix representing a rotation.\n" +"\n" +" :arg angle: The angle of rotation desired.\n" +" :type angle: float\n" +" :arg size: The size of the rotation matrix to construct [2, 4].\n" +" :type size: int\n" +" :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object (optional when size is 2).\n" +" :type axis: string or vector\n" +" :return: A new rotation matrix.\n" +" :rtype: Matrix\n"; + static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) { - VectorObject *vec = NULL; - char *axis = NULL; + VectorObject *vec= NULL; + char *axis= NULL; int matSize; float angle = 0.0f; float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - if(!PyArg_ParseTuple(args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n"); + if(!PyArg_ParseTuple(args, "fi|O", &angle, &matSize, &vec)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(angle, size, axis): expected float int and a string or vector\n"); return NULL; } + if(vec && !VectorObject_Check(vec)) { + axis= _PyUnicode_AsString((PyObject *)vec); + if(axis==NULL || axis[0]=='\0' || axis[1]!='\0' || axis[0] < 'X' || axis[0] > 'Z') { + PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): 3rd argument axis value must be a 3D vector or a string in 'X', 'Y', 'Z'\n"); + return NULL; + } + else { + /* use the string */ + vec= NULL; + } + } + #ifdef USE_MATHUTILS_DEG /* Clamp to -360:360 */ while (angle<-360.0f) @@ -379,23 +184,17 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); return NULL; } - if(matSize == 2 && (axis != NULL || vec != NULL)) { + if(matSize == 2 && (vec != NULL)) { PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n"); return NULL; } - if((matSize == 3 || matSize == 4) && axis == NULL) { + if((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) { PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n"); return NULL; } - if(axis) { - if(((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) && vec == NULL) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n"); - return NULL; - } - } if(vec) { if(vec->size != 3) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n"); + PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the vector axis must be a 3D vector\n"); return NULL; } @@ -414,35 +213,32 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) mat[1] = (float) sin (angle); mat[2] = -((float) sin(angle)); mat[3] = (float) cos(angle); - } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) { + } else if(strcmp(axis, "X") == 0) { //rotation around X mat[0] = 1.0f; mat[4] = (float) cos(angle); mat[5] = (float) sin(angle); mat[7] = -((float) sin(angle)); mat[8] = (float) cos(angle); - } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) { + } else if(strcmp(axis, "Y") == 0) { //rotation around Y mat[0] = (float) cos(angle); mat[2] = -((float) sin(angle)); mat[4] = 1.0f; mat[6] = (float) sin(angle); mat[8] = (float) cos(angle); - } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) { + } else if(strcmp(axis, "Z") == 0) { //rotation around Z mat[0] = (float) cos(angle); mat[1] = (float) sin(angle); mat[3] = -((float) sin(angle)); mat[4] = (float) cos(angle); mat[8] = 1.0f; - } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) { - //arbitrary rotation - axis_angle_to_mat3( (float (*)[3])mat,vec->vec, angle); - } else { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n"); - return NULL; + /* check for valid vector/axis above */ + axis_angle_to_mat3( (float (*)[3])mat,vec->vec, angle); } + if(matSize == 4) { //resize matrix mat[10] = mat[8]; @@ -457,8 +253,17 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) //pass to matrix creation return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); } -//----------------------------------Mathutils.TranslationMatrix() ------- -//creates a translation matrix + +static char M_Mathutils_TranslationMatrix_doc[] = +".. function:: TranslationMatrix(vector)\n" +"\n" +" Create a matrix representing a translation.\n" +"\n" +" :arg vector: The translation vector.\n" +" :type vector: Vector\n" +" :return: An identity matrix with a translation.\n" +" :rtype: Matrix\n"; + static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec) { float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, @@ -486,7 +291,20 @@ static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * v } //----------------------------------Mathutils.ScaleMatrix() ------------- //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates a scaling matrix +static char M_Mathutils_ScaleMatrix_doc[] = +".. function:: ScaleMatrix(factor, size, axis)\n" +"\n" +" Create a matrix representing a scaling.\n" +"\n" +" :arg factor: The factor of scaling to apply.\n" +" :type factor: float\n" +" :arg size: The size of the scale matrix to construct [2, 4].\n" +" :type size: int\n" +" :arg axis: Direction to influence scale. (optional).\n" +" :type axis: Vector\n" +" :return: A new scale matrix.\n" +" :rtype: Matrix\n"; + static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) { VectorObject *vec = NULL; @@ -564,7 +382,19 @@ static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) } //----------------------------------Mathutils.OrthoProjectionMatrix() --- //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates an ortho projection matrix +static char M_Mathutils_OrthoProjectionMatrix_doc[] = +".. function:: OrthoProjectionMatrix(plane, size, axis)\n" +"\n" +" Create a matrix to represent an orthographic projection.\n" +"\n" +" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ', 'R'], where a single axis is for a 2D matrix and 'R' requires axis is given.\n" +" :type plane: string\n" +" :arg size: The size of the projection matrix to construct [2, 4].\n" +" :type size: int\n" +" :arg axis: Arbitrary perpendicular plane vector.\n" +" :type axis: vector (optional)\n" +" :return: A new projection matrix.\n" +" :rtype: Matrix\n"; static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args) { VectorObject *vec = NULL; @@ -593,30 +423,21 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a } if(vec == NULL) { //ortho projection onto cardinal plane - if(((strcmp(plane, "x") == 0) - || (strcmp(plane, "X") == 0)) && matSize == 2) { + if((strcmp(plane, "X") == 0) && matSize == 2) { mat[0] = 1.0f; - } else if(((strcmp(plane, "y") == 0) - || (strcmp(plane, "Y") == 0)) - && matSize == 2) { + } else if((strcmp(plane, "Y") == 0) && matSize == 2) { mat[3] = 1.0f; - } else if(((strcmp(plane, "xy") == 0) - || (strcmp(plane, "XY") == 0)) - && matSize > 2) { + } else if((strcmp(plane, "XY") == 0) && matSize > 2) { mat[0] = 1.0f; mat[4] = 1.0f; - } else if(((strcmp(plane, "xz") == 0) - || (strcmp(plane, "XZ") == 0)) - && matSize > 2) { + } else if((strcmp(plane, "XZ") == 0) && matSize > 2) { mat[0] = 1.0f; mat[8] = 1.0f; - } else if(((strcmp(plane, "yz") == 0) - || (strcmp(plane, "YZ") == 0)) - && matSize > 2) { + } else if((strcmp(plane, "YZ") == 0) && matSize > 2) { mat[4] = 1.0f; mat[8] = 1.0f; } else { - PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n"); + PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: X, Y, XY, XZ, YZ\n"); return NULL; } } else { //arbitrary plane @@ -628,15 +449,12 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a for(x = 0; x < vec->size; x++) { vec->vec[x] /= norm; } - if(((strcmp(plane, "r") == 0) - || (strcmp(plane, "R") == 0)) && matSize == 2) { + if((strcmp(plane, "R") == 0) && matSize == 2) { 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) { + } else if((strcmp(plane, "R") == 0) && matSize > 2) { 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]); @@ -665,8 +483,21 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a //pass to matrix creation return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); } -//----------------------------------Mathutils.ShearMatrix() ------------- -//creates a shear matrix + +static char M_Mathutils_ShearMatrix_doc[] = +".. function:: ShearMatrix(plane, factor, size)\n" +"\n" +" Create a matrix to represent an shear transformation.\n" +"\n" +" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'], where a single axis is for a 2D matrix.\n" +" :type plane: string\n" +" :arg factor: The factor of shear to apply.\n" +" :type factor: float\n" +" :arg size: The size of the shear matrix to construct [2, 4].\n" +" :type size: int\n" +" :return: A new shear matrix.\n" +" :rtype: Matrix\n"; + static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) { int matSize; @@ -684,31 +515,27 @@ static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) return NULL; } - if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0)) + if((strcmp(plane, "X") == 0) && matSize == 2) { mat[0] = 1.0f; mat[2] = factor; mat[3] = 1.0f; - } else if(((strcmp(plane, "y") == 0) - || (strcmp(plane, "Y") == 0)) && matSize == 2) { + } else if((strcmp(plane, "Y") == 0) && matSize == 2) { mat[0] = 1.0f; mat[1] = factor; mat[3] = 1.0f; - } else if(((strcmp(plane, "xy") == 0) - || (strcmp(plane, "XY") == 0)) && matSize > 2) { + } else if((strcmp(plane, "XY") == 0) && matSize > 2) { mat[0] = 1.0f; mat[4] = 1.0f; mat[6] = factor; mat[7] = factor; - } else if(((strcmp(plane, "xz") == 0) - || (strcmp(plane, "XZ") == 0)) && matSize > 2) { + } else if((strcmp(plane, "XZ") == 0) && matSize > 2) { mat[0] = 1.0f; mat[3] = factor; mat[4] = 1.0f; mat[5] = factor; mat[8] = 1.0f; - } else if(((strcmp(plane, "yz") == 0) - || (strcmp(plane, "YZ") == 0)) && matSize > 2) { + } else if((strcmp(plane, "YZ") == 0) && matSize > 2) { mat[0] = 1.0f; mat[1] = factor; mat[2] = factor; @@ -732,375 +559,6 @@ static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) //pass to matrix creation return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); } -//----------------------------------QUATERNION FUNCTIONS----------------- - -//----------------------------------Mathutils.DifferenceQuats() --------- -//returns the difference between 2 quaternions -static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args) -{ - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4], tempQuat[4]; - double dot = 0.0f; - int x; - - if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, &quaternion_Type, &quatV)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types"); - return NULL; - } - - if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV)) - return NULL; - - tempQuat[0] = quatU->quat[0]; - tempQuat[1] = -quatU->quat[1]; - tempQuat[2] = -quatU->quat[2]; - tempQuat[3] = -quatU->quat[3]; - - dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] + - tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]); - - for(x = 0; x < 4; x++) { - tempQuat[x] /= (float)(dot * dot); - } - mul_qt_qtqt(quat, tempQuat, quatV->quat); - return newQuaternionObject(quat, Py_NEW, NULL); -} -//----------------------------------Mathutils.Slerp() ------------------ -//attemps to interpolate 2 quaternions and return the result -static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args) -{ - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4], quat_u[4], quat_v[4], param; - double x, y, dot, sinT, angle, IsinT; - int z; - - if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, &quatU, &quaternion_Type, &quatV, ¶m)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float"); - return NULL; - } - - if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV)) - return NULL; - - if(param > 1.0f || param < 0.0f) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0"); - return NULL; - } - - //copy quats - for(z = 0; z < 4; z++){ - quat_u[z] = quatU->quat[z]; - quat_v[z] = quatV->quat[z]; - } - - //dot product - dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] + - quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3]; - - //if negative negate a quat (shortest arc) - if(dot < 0.0f) { - quat_v[0] = -quat_v[0]; - quat_v[1] = -quat_v[1]; - quat_v[2] = -quat_v[2]; - quat_v[3] = -quat_v[3]; - dot = -dot; - } - if(dot > .99999f) { //very close - x = 1.0f - param; - y = param; - } else { - //calculate sin of angle - sinT = sqrt(1.0f - (dot * dot)); - //calculate angle - angle = atan2(sinT, dot); - //caluculate inverse of sin(theta) - IsinT = 1.0f / sinT; - x = sin((1.0f - param) * angle) * IsinT; - y = sin(param * angle) * IsinT; - } - //interpolate - quat[0] = (float)(quat_u[0] * x + quat_v[0] * y); - quat[1] = (float)(quat_u[1] * x + quat_v[1] * y); - quat[2] = (float)(quat_u[2] * x + quat_v[2] * y); - quat[3] = (float)(quat_u[3] * x + quat_v[3] * y); - - return newQuaternionObject(quat, Py_NEW, NULL); -} -//----------------------------------EULER FUNCTIONS---------------------- -//---------------------------------INTERSECTION FUNCTIONS-------------------- -//----------------------------------Mathutils.Intersect() ------------------- -static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ) -{ - VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; - float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; - float det, inv_det, u, v, t; - int clip = 1; - - if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) { - PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" ); - return NULL; - } - if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { - PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off)) - return NULL; - - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - - VECCOPY(dir, ray->vec); - normalize_v3(dir); - - VECCOPY(orig, ray_off->vec); - - /* find vectors for two edges sharing v1 */ - sub_v3_v3v3(e1, v2, v1); - sub_v3_v3v3(e2, v3, v1); - - /* begin calculating determinant - also used to calculated U parameter */ - cross_v3_v3v3(pvec, dir, e2); - - /* if determinant is near zero, ray lies in plane of triangle */ - det = dot_v3v3(e1, pvec); - - if (det > -0.000001 && det < 0.000001) { - Py_RETURN_NONE; - } - - inv_det = 1.0f / det; - - /* calculate distance from v1 to ray origin */ - sub_v3_v3v3(tvec, orig, v1); - - /* calculate U parameter and test bounds */ - u = dot_v3v3(tvec, pvec) * inv_det; - if (clip && (u < 0.0f || u > 1.0f)) { - Py_RETURN_NONE; - } - - /* prepare to test the V parameter */ - cross_v3_v3v3(qvec, tvec, e1); - - /* calculate V parameter and test bounds */ - v = dot_v3v3(dir, qvec) * inv_det; - - if (clip && (v < 0.0f || u + v > 1.0f)) { - Py_RETURN_NONE; - } - - /* calculate t, ray intersects triangle */ - t = dot_v3v3(e2, qvec) * inv_det; - - mul_v3_fl(dir, t); - add_v3_v3v3(pvec, orig, dir); - - return newVectorObject(pvec, 3, Py_NEW, NULL); -} -//----------------------------------Mathutils.LineIntersect() ------------------- -/* Line-Line intersection using algorithm from mathworld.wolfram.com */ -static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ) -{ - PyObject * tuple; - VectorObject *vec1, *vec2, *vec3, *vec4; - float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; - - if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) { - PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4)) - return NULL; - - if( vec1->size == 3 || vec1->size == 2) { - int result; - - if (vec1->size == 3) { - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - VECCOPY(v4, vec4->vec); - } - else { - v1[0] = vec1->vec[0]; - v1[1] = vec1->vec[1]; - v1[2] = 0.0f; - - v2[0] = vec2->vec[0]; - v2[1] = vec2->vec[1]; - v2[2] = 0.0f; - - v3[0] = vec3->vec[0]; - v3[1] = vec3->vec[1]; - v3[2] = 0.0f; - - v4[0] = vec4->vec[0]; - v4[1] = vec4->vec[1]; - v4[2] = 0.0f; - } - - result = isect_line_line_v3(v1, v2, v3, v4, i1, i2); - - if (result == 0) { - /* colinear */ - Py_RETURN_NONE; - } - else { - tuple = PyTuple_New( 2 ); - PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL) ); - PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL) ); - return tuple; - } - } - else { - PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" ); - return NULL; - } -} - - - -//---------------------------------NORMALS FUNCTIONS-------------------- -//----------------------------------Mathutils.QuadNormal() ------------------- -static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ) -{ - VectorObject *vec1; - VectorObject *vec2; - VectorObject *vec3; - VectorObject *vec4; - float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3]; - - if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) { - PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); - return NULL; - } - if( vec1->size != 3 ) { - PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4)) - return NULL; - - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - VECCOPY(v4, vec4->vec); - - /* find vectors for two edges sharing v2 */ - sub_v3_v3v3(e1, v1, v2); - sub_v3_v3v3(e2, v3, v2); - - cross_v3_v3v3(n1, e2, e1); - normalize_v3(n1); - - /* find vectors for two edges sharing v4 */ - sub_v3_v3v3(e1, v3, v4); - sub_v3_v3v3(e2, v1, v4); - - cross_v3_v3v3(n2, e2, e1); - normalize_v3(n2); - - /* adding and averaging the normals of both triangles */ - add_v3_v3v3(n1, n2, n1); - normalize_v3(n1); - - return newVectorObject(n1, 3, Py_NEW, NULL); -} - -//----------------------------Mathutils.TriangleNormal() ------------------- -static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ) -{ - VectorObject *vec1, *vec2, *vec3; - float v1[3], v2[3], v3[3], e1[3], e2[3], n[3]; - - if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" ); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size ) { - PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); - return NULL; - } - if( vec1->size != 3 ) { - PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3)) - return NULL; - - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - - /* find vectors for two edges sharing v2 */ - sub_v3_v3v3(e1, v1, v2); - sub_v3_v3v3(e2, v3, v2); - - cross_v3_v3v3(n, e2, e1); - normalize_v3(n); - - return newVectorObject(n, 3, Py_NEW, NULL); -} - -//--------------------------------- AREA FUNCTIONS-------------------- -//----------------------------------Mathutils.TriangleArea() ------------------- -static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ) -{ - VectorObject *vec1, *vec2, *vec3; - float v1[3], v2[3], v3[3]; - - if( !PyArg_ParseTuple - ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 - , &vector_Type, &vec3 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n"); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size ) { - PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3)) - return NULL; - - if (vec1->size == 3) { - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - - return PyFloat_FromDouble( area_tri_v3(v1, v2, v3) ); - } - else if (vec1->size == 2) { - v1[0] = vec1->vec[0]; - v1[1] = vec1->vec[1]; - - v2[0] = vec2->vec[0]; - v2[1] = vec2->vec[1]; - - v3[0] = vec3->vec[0]; - v3[1] = vec3->vec[1]; - - return PyFloat_FromDouble( area_tri_v2(v1, v2, v3) ); - } - else { - PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" ); - return NULL; - } -} /* Utility functions */ @@ -1219,3 +677,51 @@ void BaseMathObject_dealloc(BaseMathObject * self) Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes } +/*----------------------------MODULE INIT-------------------------*/ +struct PyMethodDef M_Mathutils_methods[] = { + {"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_O, M_Mathutils_TranslationMatrix_doc}, + {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef M_Mathutils_module_def = { + PyModuleDef_HEAD_INIT, + "Mathutils", /* m_name */ + M_Mathutils_doc, /* m_doc */ + 0, /* m_size */ + M_Mathutils_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; + +PyObject *Mathutils_Init(void) +{ + PyObject *submodule; + + if( PyType_Ready( &vector_Type ) < 0 ) + return NULL; + if( PyType_Ready( &matrix_Type ) < 0 ) + return NULL; + if( PyType_Ready( &euler_Type ) < 0 ) + return NULL; + if( PyType_Ready( &quaternion_Type ) < 0 ) + return NULL; + + submodule = PyModule_Create(&M_Mathutils_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule); + + /* each type has its own new() function */ + PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type ); + PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type ); + PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type ); + PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type ); + + mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb); + + return (submodule); +} |