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 | |
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')
-rw-r--r-- | source/blender/python/generic/Geometry.c | 357 | ||||
-rw-r--r-- | source/blender/python/generic/Mathutils.c | 842 | ||||
-rw-r--r-- | source/blender/python/generic/euler.c | 90 | ||||
-rw-r--r-- | source/blender/python/generic/matrix.c | 200 | ||||
-rw-r--r-- | source/blender/python/generic/quat.c | 464 | ||||
-rw-r--r-- | source/blender/python/generic/vector.c | 446 |
6 files changed, 1322 insertions, 1077 deletions
diff --git a/source/blender/python/generic/Geometry.c b/source/blender/python/generic/Geometry.c index 579c9d987cf..0dfddeee348 100644 --- a/source/blender/python/generic/Geometry.c +++ b/source/blender/python/generic/Geometry.c @@ -47,19 +47,14 @@ #define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp #define eps 0.000001 -/*-- forward declarations -- */ -static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq ); -static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_BarycentricTransform( PyObject * self, PyObject * args ); - /*-------------------------DOC STRINGS ---------------------------*/ static char M_Geometry_doc[] = "The Blender Geometry module\n\n"; +static char M_Geometry_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_Geometry_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined"; +static char M_Geometry_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined"; +static char M_Geometry_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined"; +static char M_Geometry_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other"; static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles"; static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None"; static char M_Geometry_ClosestPointOnLine_doc[] = "(pt, line_p1, line_p2) - takes a point and a line and returns a (Vector, float) for the point on the line, and the bool so you can know if the point was between the 2 points"; @@ -67,40 +62,280 @@ static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) - static char M_Geometry_PointInQuad2D_doc[] = "(pt, quad_p1, quad_p2, quad_p3, quad_p4) - takes 5 vectors, one is the point and the next 4 define the quad, only the x and y are used from the vectors"; static char M_Geometry_BoxPack2D_doc[] = ""; static char M_Geometry_BezierInterp_doc[] = ""; -/*-----------------------METHOD DEFINITIONS ----------------------*/ -struct PyMethodDef M_Geometry_methods[] = { - {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc}, - {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc}, - {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc}, - {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc}, - {"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc}, - {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc}, - {"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc}, - {"BarycentricTransform", ( PyCFunction ) M_Geometry_BarycentricTransform, METH_VARARGS, NULL}, - {NULL, NULL, 0, NULL} -}; -static struct PyModuleDef M_Geometry_module_def = { - PyModuleDef_HEAD_INIT, - "Geometry", /* m_name */ - M_Geometry_doc, /* m_doc */ - 0, /* m_size */ - M_Geometry_methods, /* m_methods */ - 0, /* m_reload */ - 0, /* m_traverse */ - 0, /* m_clear */ - 0, /* m_free */ -}; +//---------------------------------INTERSECTION FUNCTIONS-------------------- +//----------------------------------Mathutils.Intersect() ------------------- +static PyObject *M_Geometry_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; -/*----------------------------MODULE INIT-------------------------*/ -PyObject *Geometry_Init(void) + 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_Geometry_LineIntersect( PyObject * self, PyObject * args ) { - PyObject *submodule; - - submodule = PyModule_Create(&M_Geometry_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule); - - return (submodule); + 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_Geometry_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_Geometry_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_Geometry_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; + } } /*----------------------------------Geometry.PolyFill() -------------------*/ @@ -569,3 +804,43 @@ static PyObject *M_Geometry_BarycentricTransform(PyObject * self, PyObject * arg return newVectorObject(vec, 3, Py_NEW, NULL); } + +struct PyMethodDef M_Geometry_methods[] = { + {"Intersect", ( PyCFunction ) M_Geometry_Intersect, METH_VARARGS, M_Geometry_Intersect_doc}, + {"TriangleArea", ( PyCFunction ) M_Geometry_TriangleArea, METH_VARARGS, M_Geometry_TriangleArea_doc}, + {"TriangleNormal", ( PyCFunction ) M_Geometry_TriangleNormal, METH_VARARGS, M_Geometry_TriangleNormal_doc}, + {"QuadNormal", ( PyCFunction ) M_Geometry_QuadNormal, METH_VARARGS, M_Geometry_QuadNormal_doc}, + {"LineIntersect", ( PyCFunction ) M_Geometry_LineIntersect, METH_VARARGS, M_Geometry_LineIntersect_doc}, + {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc}, + {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc}, + {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc}, + {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc}, + {"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc}, + {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc}, + {"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc}, + {"BarycentricTransform", ( PyCFunction ) M_Geometry_BarycentricTransform, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef M_Geometry_module_def = { + PyModuleDef_HEAD_INIT, + "Geometry", /* m_name */ + M_Geometry_doc, /* m_doc */ + 0, /* m_size */ + M_Geometry_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; + +/*----------------------------MODULE INIT-------------------------*/ +PyObject *Geometry_Init(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&M_Geometry_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule); + + return (submodule); +} 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); +} diff --git a/source/blender/python/generic/euler.c b/source/blender/python/generic/euler.c index ae7a6783358..b48c45b322f 100644 --- a/source/blender/python/generic/euler.c +++ b/source/blender/python/generic/euler.c @@ -33,29 +33,6 @@ #include "BLI_blenlib.h" -//-------------------------DOC STRINGS --------------------------- - -static PyObject *Euler_Zero( EulerObject * self ); -static PyObject *Euler_Unique( EulerObject * self ); -static PyObject *Euler_ToMatrix( EulerObject * self ); -static PyObject *Euler_ToQuat( EulerObject * self ); -static PyObject *Euler_Rotate( EulerObject * self, PyObject *args ); -static PyObject *Euler_MakeCompatible( EulerObject * self, EulerObject *value ); -static PyObject *Euler_copy( EulerObject * self, PyObject *args ); - -//-----------------------METHOD DEFINITIONS ---------------------- -static struct PyMethodDef Euler_methods[] = { - {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, NULL}, - {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, NULL}, - {"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, NULL}, - {"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, NULL}, - {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL}, - {"makeCompatible", (PyCFunction) Euler_MakeCompatible, METH_O, NULL}, - {"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, NULL}, - {"copy", (PyCFunction) Euler_copy, METH_VARARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - //----------------------------------Mathutils.Euler() ------------------- //makes a new euler for you to play with static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) @@ -108,6 +85,15 @@ static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwar //-----------------------------METHODS---------------------------- //----------------------------Euler.toQuat()---------------------- //return a quaternion representation of the euler + +static char Euler_ToQuat_doc[] = +".. method:: to_quat()\n" +"\n" +" Return a quaternion representation of the euler.\n" +"\n" +" :return: Quaternion representation of the euler.\n" +" :rtype: Quaternion\n"; + static PyObject *Euler_ToQuat(EulerObject * self) { float quat[4]; @@ -132,6 +118,14 @@ static PyObject *Euler_ToQuat(EulerObject * self) } //----------------------------Euler.toMatrix()--------------------- //return a matrix representation of the euler +static char Euler_ToMatrix_doc[] = +".. method:: to_matrix()\n" +"\n" +" Return a matrix representation of the euler.\n" +"\n" +" :return: A 3x3 roation matrix representation of the euler.\n" +" :rtype: Matrix\n"; + static PyObject *Euler_ToMatrix(EulerObject * self) { float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; @@ -156,6 +150,14 @@ static PyObject *Euler_ToMatrix(EulerObject * self) } //----------------------------Euler.unique()----------------------- //sets the x,y,z values to a unique euler rotation + +static char Euler_Unique_doc[] = +".. method:: unique()\n" +"\n" +" Calculate a unique rotation for this euler. Avoids gimble lock.\n" +" :return: an instance of itself\n" +" :rtype: Euler\n"; + static PyObject *Euler_Unique(EulerObject * self) { #define PI_2 (Py_PI * 2.0) @@ -220,6 +222,13 @@ static PyObject *Euler_Unique(EulerObject * self) } //----------------------------Euler.zero()------------------------- //sets the euler to 0,0,0 +static char Euler_Zero_doc[] = +".. method:: zero()\n" +"\n" +" Set all values to zero.\n" +" :return: an instance of itself\n" +" :rtype: Euler\n"; + static PyObject *Euler_Zero(EulerObject * self) { self->eul[0] = 0.0; @@ -278,6 +287,16 @@ static PyObject *Euler_Rotate(EulerObject * self, PyObject *args) return (PyObject *)self; } +static char Euler_MakeCompatible_doc[] = +".. method:: make_compatible(other)\n" +"\n" +" Make this euler compatible with another, so interpolating between them works as intended.\n" +"\n" +" :arg other: make compatible with this rotation.\n" +" :type other: Euler\n" +" :return: an instance of itself.\n" +" :rtype: Euler\n"; + static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value) { #ifdef USE_MATHUTILS_DEG @@ -317,6 +336,17 @@ static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value) //----------------------------Euler.rotate()----------------------- // return a copy of the euler + +static char Euler_copy_doc[] = +".. function:: copy()\n" +"\n" +" Returns a copy of this euler.\n" +"\n" +" :return: A copy of the euler.\n" +" :rtype: Euler\n" +"\n" +" .. note:: use this to get a copy of a wrapped euler with no reference to the original data.\n"; + static PyObject *Euler_copy(EulerObject * self, PyObject *args) { if(!BaseMath_ReadCallback(self)) @@ -545,6 +575,20 @@ static PyGetSetDef Euler_getseters[] = { {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ }; + +//-----------------------METHOD DEFINITIONS ---------------------- +static struct PyMethodDef Euler_methods[] = { + {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, Euler_Zero_doc}, + {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, Euler_Unique_doc}, + {"to_matrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, Euler_ToMatrix_doc}, + {"to_quat", (PyCFunction) Euler_ToQuat, METH_NOARGS, Euler_ToQuat_doc}, + {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL}, + {"make_compatible", (PyCFunction) Euler_MakeCompatible, METH_O, Euler_MakeCompatible_doc}, + {"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, Euler_copy_doc}, + {"copy", (PyCFunction) Euler_copy, METH_VARARGS, Euler_copy_doc}, + {NULL, NULL, 0, NULL} +}; + //------------------PY_OBECT DEFINITION-------------------------- PyTypeObject euler_Type = { PyVarObject_HEAD_INIT(NULL, 0) diff --git a/source/blender/python/generic/matrix.c b/source/blender/python/generic/matrix.c index 074a397b6d9..00749002e59 100644 --- a/source/blender/python/generic/matrix.c +++ b/source/blender/python/generic/matrix.c @@ -105,39 +105,6 @@ Mathutils_Callback mathutils_matrix_vector_cb = { }; /* matrix vector callbacks, this is so you can do matrix[i][j] = val */ -/*-------------------------DOC STRINGS ---------------------------*/ - -static PyObject *Matrix_Zero( MatrixObject * self ); -static PyObject *Matrix_Identity( MatrixObject * self ); -static PyObject *Matrix_Transpose( MatrixObject * self ); -static PyObject *Matrix_Determinant( MatrixObject * self ); -static PyObject *Matrix_Invert( MatrixObject * self ); -static PyObject *Matrix_TranslationPart( MatrixObject * self ); -static PyObject *Matrix_RotationPart( MatrixObject * self ); -static PyObject *Matrix_scalePart( MatrixObject * self ); -static PyObject *Matrix_Resize4x4( MatrixObject * self ); -static PyObject *Matrix_toEuler( MatrixObject * self, PyObject *args ); -static PyObject *Matrix_toQuat( MatrixObject * self ); -static PyObject *Matrix_copy( MatrixObject * self ); - -/*-----------------------METHOD DEFINITIONS ----------------------*/ -static struct PyMethodDef Matrix_methods[] = { - {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, NULL}, - {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, NULL}, - {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, NULL}, - {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, NULL}, - {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, NULL}, - {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, NULL}, - {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, NULL}, - {"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, NULL}, - {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, NULL}, - {"toEuler", (PyCFunction) Matrix_toEuler, METH_VARARGS, NULL}, - {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, NULL}, - {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, NULL}, - {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - //----------------------------------Mathutils.Matrix() ----------------- //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. //create a new matrix type @@ -214,8 +181,33 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return newMatrixObject(matrix, argSize, seqSize, Py_NEW, NULL); } +/* assumes rowsize == colsize is checked and the read callback has run */ +static float matrix_determinant(MatrixObject * self) +{ + if(self->rowSize == 2) { + return determinant_m2(self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1]); + } else if(self->rowSize == 3) { + return determinant_m3(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 { + return determinant_m4((float (*)[4]) *self->matrix); + } +} + + /*-----------------------------METHODS----------------------------*/ -/*---------------------------Matrix.toQuat() ---------------------*/ +static char Matrix_toQuat_doc[] = +".. method:: to_quat()\n" +"\n" +" Return a quaternion representation of the rotation matrix.\n" +"\n" +" :return: Quaternion representation of the rotation matrix.\n" +" :rtype: Quaternion\n"; + static PyObject *Matrix_toQuat(MatrixObject * self) { float quat[4]; @@ -237,6 +229,16 @@ static PyObject *Matrix_toQuat(MatrixObject * self) return newQuaternionObject(quat, Py_NEW, NULL); } /*---------------------------Matrix.toEuler() --------------------*/ +static char Matrix_toEuler_doc[] = +".. method:: to_euler(euler_compat)\n" +"\n" +" Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).\n" +"\n" +" :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n" +" :type euler_compat: Euler\n" +" :return: Euler representation of the matrix.\n" +" :rtype: Euler\n"; + PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args) { float eul[3], eul_compatf[3]; @@ -288,6 +290,13 @@ PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args) return newEulerObject(eul, Py_NEW, NULL); } /*---------------------------Matrix.resize4x4() ------------------*/ +static char Matrix_Resize4x4_doc[] = +".. method:: resize4x4()\n" +"\n" +" Resize the matrix to 4x4.\n" +" :return: an instance of itself.\n" +" :rtype: Vector\n"; + PyObject *Matrix_Resize4x4(MatrixObject * self) { int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index; @@ -345,6 +354,15 @@ PyObject *Matrix_Resize4x4(MatrixObject * self) return (PyObject *)self; } /*---------------------------Matrix.translationPart() ------------*/ +static char Matrix_TranslationPart_doc[] = +".. method:: translation_part()\n" +"\n" +" Return a the translation part of a 4 row matrix.\n" +" :return: Return a the translation of a matrix.\n" +" :rtype: Matrix\n" +"\n" +" .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n"; + PyObject *Matrix_TranslationPart(MatrixObject * self) { float vec[4]; @@ -364,6 +382,15 @@ PyObject *Matrix_TranslationPart(MatrixObject * self) return newVectorObject(vec, 3, Py_NEW, NULL); } /*---------------------------Matrix.rotationPart() ---------------*/ +static char Matrix_RotationPart_doc[] = +".. method:: rotation_part()\n" +"\n" +" Return the 3d submatrix corresponding to the linear term of the embedded affine transformation in 3d. This matrix represents rotation and scale.\n" +" :return: Return the 3d matrix for rotation and scale.\n" +" :rtype: Matrix\n" +"\n" +" .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n"; + PyObject *Matrix_RotationPart(MatrixObject * self) { float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, @@ -390,6 +417,15 @@ PyObject *Matrix_RotationPart(MatrixObject * self) return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self)); } /*---------------------------Matrix.scalePart() --------------------*/ +static char Matrix_scalePart_doc[] = +".. method:: scale_part()\n" +"\n" +" Return a the scale part of a 3x3 or 4x4 matrix.\n" +" :return: Return a the scale of a matrix.\n" +" :rtype: Vector\n" +"\n" +" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"; + PyObject *Matrix_scalePart(MatrixObject * self) { float scale[3], rot[3]; @@ -419,12 +455,22 @@ PyObject *Matrix_scalePart(MatrixObject * self) return newVectorObject(scale, 3, Py_NEW, NULL); } /*---------------------------Matrix.invert() ---------------------*/ +static char Matrix_Invert_doc[] = +".. method:: invert()\n" +"\n" +" Set the matrix to its inverse.\n" +" :return: an instance of itself.\n" +" :rtype: Matrix\n" +"\n" +" .. note:: :exc:`ValueError` exception is raised.\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"; + PyObject *Matrix_Invert(MatrixObject * self) { int x, y, z = 0; float det = 0.0f; - PyObject *f = NULL; 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}; @@ -437,9 +483,7 @@ PyObject *Matrix_Invert(MatrixObject * self) } /*calculate the determinant*/ - f = Matrix_Determinant(self); - det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/ - Py_DECREF(f); + det = matrix_determinant(self); if(det != 0) { /*calculate the classical adjoint*/ @@ -478,10 +522,17 @@ PyObject *Matrix_Invert(MatrixObject * self) /*---------------------------Matrix.determinant() ----------------*/ +static char Matrix_Determinant_doc[] = +".. method:: determinant()\n" +"\n" +" Return the determinant of a matrix.\n" +" :return: Return a the determinant of a matrix.\n" +" :rtype: float\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"; + PyObject *Matrix_Determinant(MatrixObject * self) { - float det = 0.0f; - if(!BaseMath_ReadCallback(self)) return NULL; @@ -490,22 +541,18 @@ PyObject *Matrix_Determinant(MatrixObject * self) return NULL; } - if(self->rowSize == 2) { - det = determinant_m2(self->matrix[0][0], self->matrix[0][1], - self->matrix[1][0], self->matrix[1][1]); - } else if(self->rowSize == 3) { - det = determinant_m3(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 { - det = determinant_m4((float (*)[4]) *self->matrix); - } - - return PyFloat_FromDouble( (double) det ); + return PyFloat_FromDouble((double)matrix_determinant(self)); } /*---------------------------Matrix.transpose() ------------------*/ +static char Matrix_Transpose_doc[] = +".. method:: transpose()\n" +"\n" +" Set the matrix to its transpose.\n" +" :return: an instance of itself\n" +" :rtype: Matrix\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"; + PyObject *Matrix_Transpose(MatrixObject * self) { float t = 0.0f; @@ -535,6 +582,13 @@ PyObject *Matrix_Transpose(MatrixObject * self) /*---------------------------Matrix.zero() -----------------------*/ +static char Matrix_Zero_doc[] = +".. method:: zero()\n" +"\n" +" Set all the matrix values to zero.\n" +" :return: an instance of itself\n" +" :rtype: Matrix\n"; + PyObject *Matrix_Zero(MatrixObject * self) { int row, col; @@ -552,6 +606,17 @@ PyObject *Matrix_Zero(MatrixObject * self) return (PyObject *)self; } /*---------------------------Matrix.identity(() ------------------*/ +static char Matrix_Identity_doc[] = +".. method:: identity()\n" +"\n" +" Set the matrix to the identity matrix.\n" +" :return: an instance of itself\n" +" :rtype: Matrix\n" +"\n" +" .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"; + PyObject *Matrix_Identity(MatrixObject * self) { if(!BaseMath_ReadCallback(self)) @@ -580,7 +645,14 @@ PyObject *Matrix_Identity(MatrixObject * self) return (PyObject *)self; } -/*---------------------------Matrix.inverted() ------------------*/ +/*---------------------------Matrix.copy() ------------------*/ +static char Matrix_copy_doc[] = +".. method:: copy()\n" +"\n" +" Returns a copy of this matrix.\n" +" :return: an instance of itself\n" +" :rtype: Matrix\n"; + PyObject *Matrix_copy(MatrixObject * self) { if(!BaseMath_ReadCallback(self)) @@ -1162,6 +1234,24 @@ static PyGetSetDef Matrix_getseters[] = { {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ }; +/*-----------------------METHOD DEFINITIONS ----------------------*/ +static 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}, + {"translation_part", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc}, + {"rotation_part", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc}, + {"scale_part", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc}, + {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc}, + {"to_euler", (PyCFunction) Matrix_toEuler, METH_VARARGS, Matrix_toEuler_doc}, + {"to_quat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc}, + {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, + {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, + {NULL, NULL, 0, NULL} +}; + /*------------------PY_OBECT DEFINITION--------------------------*/ PyTypeObject matrix_Type = { PyVarObject_HEAD_INIT(NULL, 0) diff --git a/source/blender/python/generic/quat.c b/source/blender/python/generic/quat.c index e739e1a5036..7facc350625 100644 --- a/source/blender/python/generic/quat.c +++ b/source/blender/python/generic/quat.c @@ -32,137 +32,17 @@ #include "BKE_utildefines.h" #include "BLI_blenlib.h" - -//-------------------------DOC STRINGS --------------------------- - -static PyObject *Quaternion_Identity( QuaternionObject * self ); -static PyObject *Quaternion_Negate( QuaternionObject * self ); -static PyObject *Quaternion_Conjugate( QuaternionObject * self ); -static PyObject *Quaternion_Inverse( QuaternionObject * self ); -static PyObject *Quaternion_Normalize( QuaternionObject * self ); -static PyObject *Quaternion_ToEuler( QuaternionObject * self, PyObject *args ); -static PyObject *Quaternion_ToMatrix( QuaternionObject * self ); -static PyObject *Quaternion_Cross( QuaternionObject * self, QuaternionObject * value ); -static PyObject *Quaternion_Dot( QuaternionObject * self, QuaternionObject * value ); -static PyObject *Quaternion_copy( QuaternionObject * self ); - -//-----------------------METHOD DEFINITIONS ---------------------- -static struct PyMethodDef Quaternion_methods[] = { - {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, NULL}, - {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, NULL}, - {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, NULL}, - {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, NULL}, - {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, NULL}, - {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, NULL}, - {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, NULL}, - {"cross", (PyCFunction) Quaternion_Cross, METH_O, NULL}, - {"dot", (PyCFunction) Quaternion_Dot, METH_O, NULL}, - {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL}, - {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -//----------------------------------Mathutils.Quaternion() -------------- -static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *listObject = NULL, *n, *q; - int size, i; - float quat[4]; - double angle = 0.0f; - - size = PyTuple_GET_SIZE(args); - if (size == 1 || size == 2) { //seq? - listObject = PyTuple_GET_ITEM(args, 0); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - if ((size == 4 && PySequence_Length(args) !=1) || - (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { - // invalid args/size - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - if(size == 3){ //get angle in axis/angle - n = PySequence_GetItem(args, 1); - if(n == NULL) { // parsed item not a number or getItem fail - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - - angle = PyFloat_AsDouble(n); - Py_DECREF(n); - - if (angle==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - }else{ - listObject = PyTuple_GET_ITEM(args, 1); - if (size>1 && PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - if (size != 3) { - // invalid args/size - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0)); - - if (angle==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } else { // argument was not a sequence - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - } else if (size == 0) { //returns a new empty quat - return newQuaternionObject(NULL, Py_NEW, NULL); - } else { - listObject = args; - } - - if (size == 3) { // invalid quat size - if(PySequence_Length(args) != 2){ - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - }else{ - if(size != 4){ - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - - for (i=0; i<size; i++) { //parse - q = PySequence_GetItem(listObject, i); - if (q == NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - - quat[i] = PyFloat_AsDouble(q); - Py_DECREF(q); - - if (quat[i]==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - - if(size == 3) //calculate the quat based on axis/angle -#ifdef USE_MATHUTILS_DEG - axis_angle_to_quat(quat, quat, angle * (Py_PI / 180)); -#else - axis_angle_to_quat(quat, quat, angle); -#endif - - return newQuaternionObject(quat, Py_NEW, NULL); -} - //-----------------------------METHODS------------------------------ -//----------------------------Quaternion.toEuler()------------------ -//return the quat as a euler +static char Quaternion_ToEuler_doc[] = +".. method:: to_euler(euler_compat)\n" +"\n" +" Return Euler representation of the quaternion.\n" +"\n" +" :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n" +" :type euler_compat: Euler\n" +" :return: Euler representation of the quaternion.\n" +" :rtype: Euler\n"; + static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args) { float eul[3]; @@ -212,7 +92,14 @@ static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args) return newEulerObject(eul, Py_NEW, NULL); } //----------------------------Quaternion.toMatrix()------------------ -//return the quat as a matrix +static char Quaternion_ToMatrix_doc[] = +".. method:: to_matrix(other)\n" +"\n" +" Return a matrix representation of the quaternion.\n" +"\n" +" :return: A 3x3 rotation matrix representation of the quaternion.\n" +" :rtype: Matrix\n"; + static PyObject *Quaternion_ToMatrix(QuaternionObject * self) { float mat[9]; /* all values are set */ @@ -225,7 +112,16 @@ static PyObject *Quaternion_ToMatrix(QuaternionObject * self) } //----------------------------Quaternion.cross(other)------------------ -//return the cross quat +static char Quaternion_Cross_doc[] = +".. method:: cross(other)\n" +"\n" +" Return the cross product of this quaternion and another.\n" +"\n" +" :arg other: The other quaternion to perform the cross product with.\n" +" :type other: Quaternion\n" +" :return: The cross product.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value) { float quat[4]; @@ -243,7 +139,16 @@ static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * va } //----------------------------Quaternion.dot(other)------------------ -//return the dot quat +static char Quaternion_Dot_doc[] = +".. method:: dot(other)\n" +"\n" +" Return the dot product of this quaternion and another.\n" +"\n" +" :arg other: The other quaternion to perform the dot product with.\n" +" :type other: Quaternion\n" +" :return: The dot product.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value) { if (!QuaternionObject_Check(value)) { @@ -257,8 +162,90 @@ static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * valu return PyFloat_FromDouble(dot_qtqt(self->quat, value->quat)); } +static char Quaternion_Difference_doc[] = +".. function:: difference(other)\n" +"\n" +" Returns a quaternion representing the rotational difference.\n" +"\n" +" :arg other: second quaternion.\n" +" :type other: Quaternion\n" +" :return: the rotational difference between the two quat rotations.\n" +" :rtype: Quaternion\n"; + +static PyObject *Quaternion_Difference(QuaternionObject * self, QuaternionObject * value) +{ + float quat[4], tempQuat[4]; + double dot = 0.0f; + int x; + + if (!QuaternionObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "quat.difference(value): expected a quaternion argument" ); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + tempQuat[0] = self->quat[0]; + tempQuat[1] = - self->quat[1]; + tempQuat[2] = - self->quat[2]; + tempQuat[3] = - self->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, value->quat); + return newQuaternionObject(quat, Py_NEW, NULL); +} + +static char Quaternion_Slerp_doc[] = +".. function:: slerp(other, factor)\n" +"\n" +" Returns the interpolation of two quaternions.\n" +"\n" +" :arg other: value to interpolate with.\n" +" :type other: Quaternion\n" +" :arg factor: The interpolation value in [0.0, 1.0].\n" +" :type factor: float\n" +" :return: The interpolated rotation.\n" +" :rtype: Quaternion\n"; + +static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args) +{ + QuaternionObject *value; + float quat[4], fac; + + if(!PyArg_ParseTuple(args, "O!f", &quaternion_Type, &value, &fac)) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float"); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + if(fac > 1.0f || fac < 0.0f) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0"); + return NULL; + } + + interp_qt_qtqt(quat, self->quat, value->quat, fac); + + return newQuaternionObject(quat, Py_NEW, NULL); +} + //----------------------------Quaternion.normalize()---------------- //normalize the axis of rotation of [theta,vector] +static char Quaternion_Normalize_doc[] = +".. function:: normalize()\n" +"\n" +" Normalize the quaternion.\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Normalize(QuaternionObject * self) { if(!BaseMath_ReadCallback(self)) @@ -271,7 +258,14 @@ static PyObject *Quaternion_Normalize(QuaternionObject * self) return (PyObject*)self; } //----------------------------Quaternion.inverse()------------------ -//invert the quat +static char Quaternion_Inverse_doc[] = +".. function:: inverse()\n" +"\n" +" Set the quaternion to its inverse.\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Inverse(QuaternionObject * self) { if(!BaseMath_ReadCallback(self)) @@ -284,7 +278,14 @@ static PyObject *Quaternion_Inverse(QuaternionObject * self) return (PyObject*)self; } //----------------------------Quaternion.identity()----------------- -//generate the identity quaternion +static char Quaternion_Identity_doc[] = +".. function:: identity()\n" +"\n" +" Set the quaternion to an identity quaternion.\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Identity(QuaternionObject * self) { if(!BaseMath_ReadCallback(self)) @@ -297,7 +298,14 @@ static PyObject *Quaternion_Identity(QuaternionObject * self) return (PyObject*)self; } //----------------------------Quaternion.negate()------------------- -//negate the quat +static char Quaternion_Negate_doc[] = +".. function:: negate()\n" +"\n" +" Set the quaternion to its negative.\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Negate(QuaternionObject * self) { if(!BaseMath_ReadCallback(self)) @@ -310,7 +318,14 @@ static PyObject *Quaternion_Negate(QuaternionObject * self) return (PyObject*)self; } //----------------------------Quaternion.conjugate()---------------- -//negate the vector part +static char Quaternion_Conjugate_doc[] = +".. function:: conjugate()\n" +"\n" +" Set the quaternion to its conjugate (negate x, y, z).\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: Quaternion\n"; + static PyObject *Quaternion_Conjugate(QuaternionObject * self) { if(!BaseMath_ReadCallback(self)) @@ -323,7 +338,16 @@ static PyObject *Quaternion_Conjugate(QuaternionObject * self) return (PyObject*)self; } //----------------------------Quaternion.copy()---------------- -//return a copy of the quat +static char Quaternion_copy_doc[] = +".. function:: copy()\n" +"\n" +" Returns a copy of this quaternion.\n" +"\n" +" :return: A copy of the quaternion.\n" +" :rtype: Quaternion\n" +"\n" +" .. note:: use this to get a copy of a wrapped quaternion with no reference to the original data.\n"; + static PyObject *Quaternion_copy(QuaternionObject * self) { if(!BaseMath_ReadCallback(self)) @@ -702,52 +726,139 @@ static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type ) return (PyObject *) newVectorObject(vec, 3, Py_NEW, NULL); } +//----------------------------------Mathutils.Quaternion() -------------- +static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *listObject = NULL, *n, *q; + int size, i; + float quat[4]; + double angle = 0.0f; + + size = PyTuple_GET_SIZE(args); + if (size == 1 || size == 2) { //seq? + listObject = PyTuple_GET_ITEM(args, 0); + if (PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + if ((size == 4 && PySequence_Length(args) !=1) || + (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { + // invalid args/size + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + if(size == 3){ //get angle in axis/angle + n = PySequence_GetItem(args, 1); + if(n == NULL) { // parsed item not a number or getItem fail + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + + angle = PyFloat_AsDouble(n); + Py_DECREF(n); + + if (angle==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + }else{ + listObject = PyTuple_GET_ITEM(args, 1); + if (size>1 && PySequence_Check(listObject)) { + size = PySequence_Length(listObject); + if (size != 3) { + // invalid args/size + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0)); + + if (angle==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } else { // argument was not a sequence + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + } else if (size == 0) { //returns a new empty quat + return newQuaternionObject(NULL, Py_NEW, NULL); + } else { + listObject = args; + } + + if (size == 3) { // invalid quat size + if(PySequence_Length(args) != 2){ + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + }else{ + if(size != 4){ + PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + + for (i=0; i<size; i++) { //parse + q = PySequence_GetItem(listObject, i); + if (q == NULL) { // Failed to read sequence + PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + + quat[i] = PyFloat_AsDouble(q); + Py_DECREF(q); + + if (quat[i]==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + return NULL; + } + } + + if(size == 3) //calculate the quat based on axis/angle +#ifdef USE_MATHUTILS_DEG + axis_angle_to_quat(quat, quat, angle * (Py_PI / 180)); +#else + axis_angle_to_quat(quat, quat, angle); +#endif + + return newQuaternionObject(quat, Py_NEW, NULL); +} + + +//-----------------------METHOD DEFINITIONS ---------------------- +static 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}, + {"to_euler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, Quaternion_ToEuler_doc}, + {"to_matrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc}, + {"cross", (PyCFunction) Quaternion_Cross, METH_O, Quaternion_Cross_doc}, + {"dot", (PyCFunction) Quaternion_Dot, METH_O, Quaternion_Dot_doc}, + {"difference", (PyCFunction) Quaternion_Difference, METH_O, Quaternion_Difference_doc}, + {"slerp", (PyCFunction) Quaternion_Slerp, METH_VARARGS, Quaternion_Slerp_doc}, + {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, + {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, + {NULL, NULL, 0, NULL} +}; /*****************************************************************************/ /* Python attributes get/set structure: */ /*****************************************************************************/ static PyGetSetDef Quaternion_getseters[] = { - {"w", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion W value", - (void *)0}, - {"x", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion X axis", - (void *)1}, - {"y", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion Y axis", - (void *)2}, - {"z", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion Z axis", - (void *)3}, - {"magnitude", - (getter)Quaternion_getMagnitude, (setter)NULL, - "Size of the quaternion", - NULL}, - {"angle", - (getter)Quaternion_getAngle, (setter)NULL, - "angle of the quaternion", - NULL}, - {"axis", - (getter)Quaternion_getAxisVec, (setter)NULL, - "quaternion axis as a vector", - NULL}, - {"wrapped", - (getter)BaseMathObject_getWrapped, (setter)NULL, - "True when this wraps blenders internal data", - NULL}, - {"_owner", - (getter)BaseMathObject_getOwner, (setter)NULL, - "Read only owner for vectors that depend on another object", - NULL}, - + {"w", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion W value", (void *)0}, + {"x", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion X axis", (void *)1}, + {"y", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion Y axis", (void *)2}, + {"z", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, "Quaternion Z axis", (void *)3}, + {"magnitude", (getter)Quaternion_getMagnitude, (setter)NULL, "Size of the quaternion", NULL}, + {"angle", (getter)Quaternion_getAngle, (setter)NULL, "angle of the quaternion", NULL}, + {"axis",(getter)Quaternion_getAxisVec, (setter)NULL, "quaternion axis as a vector", NULL}, + {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "True when this wraps blenders internal data", NULL}, + {"_owner", (getter)BaseMathObject_getOwner, (setter)NULL, "Read only owner for vectors that depend on another object", NULL}, {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ }; - //------------------PY_OBECT DEFINITION-------------------------- PyTypeObject quaternion_Type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -843,3 +954,4 @@ PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) return (PyObject *)self; } + diff --git a/source/blender/python/generic/vector.c b/source/blender/python/generic/vector.c index 862b7338ac0..558e4aac9c9 100644 --- a/source/blender/python/generic/vector.c +++ b/source/blender/python/generic/vector.c @@ -41,37 +41,6 @@ static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */ -/*-----------------------METHOD DEFINITIONS ----------------------*/ -static PyObject *Vector_Zero( VectorObject * self ); -static PyObject *Vector_Normalize( VectorObject * self ); -static PyObject *Vector_Negate( VectorObject * self ); -static PyObject *Vector_Resize2D( VectorObject * self ); -static PyObject *Vector_Resize3D( VectorObject * self ); -static PyObject *Vector_Resize4D( VectorObject * self ); -static PyObject *Vector_ToTuple( VectorObject * self, PyObject *value ); -static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ); -static PyObject *Vector_Reflect( VectorObject *self, VectorObject *value ); -static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ); -static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ); -static PyObject *Vector_copy( VectorObject * self ); - -static struct PyMethodDef Vector_methods[] = { - {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, NULL}, - {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, NULL}, - {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, NULL}, - {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, NULL}, - {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, NULL}, - {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, NULL}, - {"toTuple", (PyCFunction) Vector_ToTuple, METH_O, NULL}, - {"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, NULL}, - {"reflect", ( PyCFunction ) Vector_Reflect, METH_O, NULL}, - {"cross", ( PyCFunction ) Vector_Cross, METH_O, NULL}, - {"dot", ( PyCFunction ) Vector_Dot, METH_O, NULL}, - {"copy", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, - {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - //----------------------------------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 @@ -124,8 +93,13 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } /*-----------------------------METHODS---------------------------- */ -/*----------------------------Vector.zero() ---------------------- - set the vector data to 0,0,0 */ +static char Vector_Zero_doc[] = +".. method:: zero()\n" +"\n" +" Set all values to zero.\n" +" :return: an instance of itself\n" +" :rtype: vector\n"; + static PyObject *Vector_Zero(VectorObject * self) { int i; @@ -137,8 +111,18 @@ static PyObject *Vector_Zero(VectorObject * self) Py_INCREF(self); return (PyObject*)self; } -/*----------------------------Vector.normalize() ----------------- - normalize the vector data to a unit vector */ +/*----------------------------Vector.normalize() ----------------- */ +static char Vector_Normalize_doc[] = +".. method:: normalize()\n" +"\n" +" Normalize the vector, making the length of the vector always 1.0.\n" +" :return: an instance of itself\n" +" :rtype: vector\n" +"\n" +" .. warning:: Normalizing a vector where all values are zero results in all axis having a nan value (not a number).\n" +"\n" +" .. note:: Normalize works for vectors of all sizes, however 4D Vectors w axis is left untouched.\n"; + static PyObject *Vector_Normalize(VectorObject * self) { int i; @@ -161,8 +145,14 @@ static PyObject *Vector_Normalize(VectorObject * self) } -/*----------------------------Vector.resize2D() ------------------ - resize the vector to x,y */ +/*----------------------------Vector.resize2D() ------------------ */ +static char Vector_Resize2D_doc[] = +".. method:: resize2D()\n" +"\n" +" Resize the vector to 2D (x, y).\n" +" :return: an instance of itself\n" +" :rtype: vector\n"; + static PyObject *Vector_Resize2D(VectorObject * self) { if(self->wrapped==Py_WRAP) { @@ -184,8 +174,14 @@ static PyObject *Vector_Resize2D(VectorObject * self) Py_INCREF(self); return (PyObject*)self; } -/*----------------------------Vector.resize3D() ------------------ - resize the vector to x,y,z */ +/*----------------------------Vector.resize3D() ------------------ */ +static char Vector_Resize3D_doc[] = +".. method:: resize3D()\n" +"\n" +" Resize the vector to 3D (x, y, z).\n" +" :return: an instance of itself\n" +" :rtype: vector\n"; + static PyObject *Vector_Resize3D(VectorObject * self) { if (self->wrapped==Py_WRAP) { @@ -210,8 +206,14 @@ static PyObject *Vector_Resize3D(VectorObject * self) Py_INCREF(self); return (PyObject*)self; } -/*----------------------------Vector.resize4D() ------------------ - resize the vector to x,y,z,w */ +/*----------------------------Vector.resize4D() ------------------ */ +static char Vector_Resize4D_doc[] = +".. method:: resize4D()\n" +"\n" +" Resize the vector to 4D (x, y, z, w).\n" +" :return: an instance of itself\n" +" :rtype: vector\n"; + static PyObject *Vector_Resize4D(VectorObject * self) { if(self->wrapped==Py_WRAP) { @@ -239,8 +241,17 @@ static PyObject *Vector_Resize4D(VectorObject * self) return (PyObject*)self; } -/*----------------------------Vector.resize4D() ------------------ - resize the vector to x,y,z,w */ +/*----------------------------Vector.toTuple() ------------------ */ +static char Vector_ToTuple_doc[] = +".. method:: to_tuple(precision)\n" +"\n" +" Return this vector as a tuple with.\n" +"\n" +" :arg precision: The number to round the value to in [0, 21].\n" +" :type precision: int\n" +" :return: the values of the vector rounded by *precision*\n" +" :rtype: tuple\n"; + static PyObject *Vector_ToTuple(VectorObject * self, PyObject *value) { int ndigits= PyLong_AsSsize_t(value); @@ -265,8 +276,19 @@ static PyObject *Vector_ToTuple(VectorObject * self, PyObject *value) return ret; } -/*----------------------------Vector.toTrackQuat(track, up) ---------------------- - extract a quaternion from the vector and the track and up axis */ +/*----------------------------Vector.toTrackQuat(track, up) ---------------------- */ +static char Vector_ToTrackQuat_doc[] = +".. method:: to_track_quat(track, up)\n" +"\n" +" Return a quaternion rotation from the vector and the track and up axis.\n" +"\n" +" :arg track: Track axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z'].\n" +" :type track: string\n" +" :arg up: Up axis in ['X', 'Y', 'Z'].\n" +" :type up: string\n" +" :return: rotation from the vector and the track and up axis." +" :rtype: Quaternion\n"; + static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) { float vec[3], quat[4]; @@ -290,14 +312,11 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) if (strack[0] == '-') { switch(strack[1]) { case 'X': - case 'x': track = 3; break; case 'Y': - case 'y': track = 4; break; - case 'z': case 'Z': track = 5; break; @@ -315,14 +334,11 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) switch(strack[0]) { case '-': case 'X': - case 'x': track = 0; break; case 'Y': - case 'y': track = 1; break; - case 'z': case 'Z': track = 2; break; @@ -341,14 +357,11 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) if (strlen(sup) == 1) { switch(*sup) { case 'X': - case 'x': up = 0; break; - case 'Y': case 'y': up = 1; break; - case 'z': case 'Z': up = 2; break; @@ -385,6 +398,16 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) return a reflected vector on the mirror normal vec - ((2 * DotVecs(vec, mirror)) * mirror) */ +static char Vector_Reflect_doc[] = +".. method:: reflect(mirror)\n" +"\n" +" Return the reflection vector from the *mirror* argument.\n" +"\n" +" :arg mirror: This vector could be a normal from the reflecting surface.\n" +" :type mirror: vector\n" +" :return: The reflected vector.\n" +" :rtype: Vector object matching the size of this vector.\n"; + static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value ) { float mirror[3], vec[3]; @@ -414,6 +437,18 @@ static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value ) return newVectorObject(reflect, self->size, Py_NEW, NULL); } +static char Vector_Cross_doc[] = +".. method:: cross(other)\n" +"\n" +" Return the cross product of this vector and another.\n" +"\n" +" :arg other: The other vector to perform the cross product with.\n" +" :type other: vector\n" +" :return: The cross product.\n" +" :rtype: Vector\n" +"\n" +" .. note:: both vectors must be 3D\n"; + static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ) { VectorObject *vecCross = NULL; @@ -436,6 +471,16 @@ static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ) return (PyObject *)vecCross; } +static char Vector_Dot_doc[] = +".. method:: dot(other)\n" +"\n" +" Return the dot product of this vector and another.\n" +"\n" +" :arg other: The other vector to perform the dot product with.\n" +" :type other: vector\n" +" :return: The dot product.\n" +" :rtype: Vector\n"; + static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ) { double dot = 0.0; @@ -460,8 +505,156 @@ static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ) return PyFloat_FromDouble(dot); } -/*----------------------------Vector.copy() -------------------------------------- - return a copy of the vector */ +static char Vector_Angle_doc[] = +".. function:: angle(other)\n" +"\n" +" Return the angle between two vectors.\n" +"\n" +" :type other: vector\n" +" :return angle: angle in radians\n" +" :rtype: float\n" +"\n" +" .. note:: Zero length vectors raise an :exc:`AttributeError`.\n"; +static PyObject *Vector_Angle(VectorObject * self, VectorObject * value) +{ + double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f; + int x, size; + + if (!VectorObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "vec.angle(value): expected a vector argument" ); + return NULL; + } + + if(self->size != value->size) { + PyErr_SetString(PyExc_AttributeError, "vec.angle(value): expects both vectors to have the same size\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + //since size is the same.... + size = self->size; + + for(x = 0; x < size; x++) { + test_v1 += self->vec[x] * self->vec[x]; + test_v2 += value->vec[x] * value->vec[x]; + } + if (!test_v1 || !test_v2){ + PyErr_SetString(PyExc_AttributeError, "vector.angle(other): zero length vectors are not acceptable arguments\n"); + return NULL; + } + + //dot product + for(x = 0; x < size; x++) { + dot += self->vec[x] * value->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 +} + +static char Vector_Project_doc[] = +".. function:: project(other)\n" +"\n" +" Return the projection of this vector onto the *other*.\n" +"\n" +" :type other: vector\n" +" :return projection: the parallel projection vector\n" +" :rtype: vector\n"; + +static PyObject *Vector_Project(VectorObject * self, VectorObject * value) +{ + float vec[4]; + double dot = 0.0f, dot2 = 0.0f; + int x, size; + + if (!VectorObject_Check(value)) { + PyErr_SetString( PyExc_TypeError, "vec.project(value): expected a vector argument" ); + return NULL; + } + + if(self->size != value->size) { + PyErr_SetString(PyExc_AttributeError, "vec.project(value): expects both vectors to have the same size\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) + return NULL; + + + //since they are the same size... + size = self->size; + + //get dot products + for(x = 0; x < size; x++) { + dot += self->vec[x] * value->vec[x]; + dot2 += value->vec[x] * value->vec[x]; + } + //projection + dot /= dot2; + for(x = 0; x < size; x++) { + vec[x] = (float)(dot * value->vec[x]); + } + return newVectorObject(vec, size, Py_NEW, NULL); +} + +//----------------------------------Mathutils.MidpointVecs() ------------- +static char Vector_Lerp_doc[] = +".. function:: lerp(other, factor)\n" +"\n" +" Returns the interpolation of two vectors.\n" +"\n" +" :arg other: value to interpolate with.\n" +" :type other: Vector\n" +" :arg factor: The interpolation value in [0.0, 1.0].\n" +" :type factor: float\n" +" :return: The interpolated rotation.\n" +" :rtype: Vector\n"; + +static PyObject *Vector_Lerp(VectorObject * self, PyObject * args) +{ + VectorObject *vec2 = NULL; + float fac, ifac, vec[4]; + int x; + + if(!PyArg_ParseTuple(args, "O!f", &vector_Type, &vec2, &fac)) { + PyErr_SetString(PyExc_TypeError, "vector.lerp(): expects a vector of the same size and float"); + return NULL; + } + if(self->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size"); + return NULL; + } + + if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(vec2)) + return NULL; + + ifac= 1.0 - fac; + + for(x = 0; x < self->size; x++) { + vec[x] = (ifac * self->vec[x]) + (fac * vec2->vec[x]); + } + return newVectorObject(vec, self->size, Py_NEW, NULL); +} + +/*----------------------------Vector.copy() -------------------------------------- */ +static char Vector_copy_doc[] = +".. function:: copy()\n" +"\n" +" Returns a copy of this vector.\n" +"\n" +" :return: A copy of the vector.\n" +" :rtype: Vector\n" +"\n" +" .. note:: use this to get a copy of a wrapped vector with no reference to the original data.\n"; + static PyObject *Vector_copy(VectorObject * self) { if(!BaseMath_ReadCallback(self)) @@ -1808,7 +2001,87 @@ if len(unique) != len(items): */ +//-----------------row_vector_multiplication (internal)----------- +//ROW VECTOR Multiplication - Vector X Matrix +//[x][y][z] * [1][4][7] +// [2][5][8] +// [3][6][9] +//vector/matrix multiplication IS NOT COMMUTATIVE!!!! +static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat) +{ + float vecNew[4], vecCopy[4]; + double dot = 0.0f; + int x, y, z = 0, vec_size = vec->size; + + if(mat->colSize != vec_size){ + if(mat->colSize == 4 && vec_size != 3){ + PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same"); + return NULL; + }else{ + vecCopy[3] = 1.0f; + } + } + + if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat)) + return NULL; + + for(x = 0; x < vec_size; x++){ + vecCopy[x] = vec->vec[x]; + } + vecNew[3] = 1.0f; + //muliplication + for(x = 0; x < mat->rowSize; x++) { + for(y = 0; y < mat->colSize; y++) { + dot += mat->matrix[x][y] * vecCopy[y]; + } + vecNew[z++] = (float)dot; + dot = 0.0f; + } + return newVectorObject(vecNew, vec_size, Py_NEW, NULL); +} + +/*----------------------------Vector.negate() -------------------- */ +static char Vector_Negate_doc[] = +".. method:: negate()\n" +"\n" +" Set all values to their negative.\n" +" :return: an instance of itself\n" +" :rtype: vector\n"; +static PyObject *Vector_Negate(VectorObject * self) +{ + int i; + if(!BaseMath_ReadCallback(self)) + return NULL; + + for(i = 0; i < self->size; i++) + self->vec[i] = -(self->vec[i]); + + BaseMath_WriteCallback(self); // alredy checked for error + + Py_INCREF(self); + return (PyObject*)self; +} + +static 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_Resize3D_doc}, + {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, Vector_Resize4D_doc}, + {"to_tuple", (PyCFunction) Vector_ToTuple, METH_O, Vector_ToTuple_doc}, + {"to_track_quat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, Vector_ToTrackQuat_doc}, + {"reflect", ( PyCFunction ) Vector_Reflect, METH_O, Vector_Reflect_doc}, + {"cross", ( PyCFunction ) Vector_Cross, METH_O, Vector_Cross_doc}, + {"dot", ( PyCFunction ) Vector_Dot, METH_O, Vector_Dot_doc}, + {"angle", ( PyCFunction ) Vector_Angle, METH_O, Vector_Angle_doc}, + {"project", ( PyCFunction ) Vector_Project, METH_O, Vector_Project_doc}, + {"lerp", ( PyCFunction ) Vector_Lerp, METH_VARARGS, Vector_Lerp_doc}, + {"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc}, + {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; /* Note @@ -1817,6 +2090,8 @@ if len(unique) != len(items): vec*mat and mat*vec both get sent to Vector_mul and it neesd to sort out the order */ +static char vector_doc[] = "This object gives access to Vectors in Blender."; + PyTypeObject vector_Type = { PyVarObject_HEAD_INIT(NULL, 0) /* For printing, in format "<module>.<name>" */ @@ -1852,7 +2127,7 @@ PyTypeObject vector_Type = { /*** Flags to define presence of optional/expanded features ***/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - NULL, /* char *tp_doc; Documentation string */ + vector_doc, /* char *tp_doc; Documentation string */ /*** Assigned meaning in release 2.0 ***/ /* call function for all accessible objects */ NULL, /* traverseproc tp_traverse; */ @@ -1897,7 +2172,6 @@ PyTypeObject vector_Type = { NULL }; - /*------------------------newVectorObject (internal)------------- creates a new vector object pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER @@ -1956,59 +2230,3 @@ PyObject *newVectorObject_cb(PyObject *cb_user, int size, int cb_type, int cb_su return (PyObject *)self; } - -//-----------------row_vector_multiplication (internal)----------- -//ROW VECTOR Multiplication - Vector X Matrix -//[x][y][z] * [1][4][7] -// [2][5][8] -// [3][6][9] -//vector/matrix multiplication IS NOT COMMUTATIVE!!!! -static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat) -{ - float vecNew[4], vecCopy[4]; - double dot = 0.0f; - int x, y, z = 0, vec_size = vec->size; - - if(mat->colSize != vec_size){ - if(mat->colSize == 4 && vec_size != 3){ - PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same"); - return NULL; - }else{ - vecCopy[3] = 1.0f; - } - } - - if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat)) - return NULL; - - for(x = 0; x < vec_size; x++){ - vecCopy[x] = vec->vec[x]; - } - vecNew[3] = 1.0f; - //muliplication - for(x = 0; x < mat->rowSize; x++) { - for(y = 0; y < mat->colSize; y++) { - dot += mat->matrix[x][y] * vecCopy[y]; - } - vecNew[z++] = (float)dot; - dot = 0.0f; - } - return newVectorObject(vecNew, vec_size, Py_NEW, NULL); -} - -/*----------------------------Vector.negate() -------------------- - set the vector to it's negative -x, -y, -z */ -static PyObject *Vector_Negate(VectorObject * self) -{ - int i; - if(!BaseMath_ReadCallback(self)) - return NULL; - - for(i = 0; i < self->size; i++) - self->vec[i] = -(self->vec[i]); - - BaseMath_WriteCallback(self); // alredy checked for error - - Py_INCREF(self); - return (PyObject*)self; -} |