4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * This is a new part of Blender.
25 * Contributor(s): Joseph Gilbert, Campbell Barton
27 * ***** END GPL LICENSE BLOCK *****
30 #include "Mathutils.h"
32 #include "BLI_arithb.h"
35 #include "BKE_utildefines.h"
37 //-------------------------DOC STRINGS ---------------------------
38 static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
39 static char M_Mathutils_Rand_doc[] = "() - return a random number";
40 static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees";
41 static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors";
42 static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB";
43 static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation";
44 static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor";
45 static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane";
46 static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor";
47 static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector";
48 static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions";
49 static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats";
50 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";
51 static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined";
52 static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined";
53 static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined";
54 static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other";
55 //-----------------------METHOD DEFINITIONS ----------------------
57 static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args);
58 static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args);
59 static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args);
60 static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args);
61 static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args);
62 static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value);
63 static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args);
64 static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args);
65 static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args);
66 static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args);
67 static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args);
68 static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args );
69 static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args );
70 static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args );
71 static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args );
72 static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args );
74 struct PyMethodDef M_Mathutils_methods[] = {
75 {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc},
76 {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc},
77 {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc},
78 {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc},
79 {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc},
80 {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc},
81 {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc},
82 {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc},
83 {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc},
84 {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc},
85 {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc},
86 {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc},
87 {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc},
88 {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc},
89 {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc},
90 {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc},
94 /*----------------------------MODULE INIT-------------------------*/
95 /* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */
97 #if (PY_VERSION_HEX >= 0x03000000)
98 static struct PyModuleDef M_Mathutils_module_def = {
99 PyModuleDef_HEAD_INIT,
100 "Mathutils", /* m_name */
101 M_Mathutils_doc, /* m_doc */
103 M_Mathutils_methods, /* m_methods */
111 PyObject *Mathutils_Init(const char *from)
115 //seed the generator for the rand function
116 BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF));
118 if( PyType_Ready( &vector_Type ) < 0 )
120 if( PyType_Ready( &matrix_Type ) < 0 )
122 if( PyType_Ready( &euler_Type ) < 0 )
124 if( PyType_Ready( &quaternion_Type ) < 0 )
127 #if (PY_VERSION_HEX >= 0x03000000)
128 submodule = PyModule_Create(&M_Mathutils_module_def);
129 PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule);
131 submodule = Py_InitModule3(from, M_Mathutils_methods, M_Mathutils_doc);
134 /* each type has its own new() function */
135 PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type );
136 PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type );
137 PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type );
138 PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type );
140 mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
145 //-----------------------------METHODS----------------------------
146 //-----------------quat_rotation (internal)-----------
147 //This function multiplies a vector/point * quat or vice versa
148 //to rotate the point/vector by the quaternion
149 //arguments should all be 3D
150 PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
153 QuaternionObject *quat = NULL;
154 VectorObject *vec = NULL;
156 if(QuaternionObject_Check(arg1)){
157 quat = (QuaternionObject*)arg1;
158 if(!BaseMath_ReadCallback(quat))
161 if(VectorObject_Check(arg2)){
162 vec = (VectorObject*)arg2;
164 if(!BaseMath_ReadCallback(vec))
167 rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
168 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
169 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
170 quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
171 rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
172 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
173 quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
174 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
175 rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
176 quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
177 quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
178 quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
179 return newVectorObject(rot, 3, Py_NEW);
181 }else if(VectorObject_Check(arg1)){
182 vec = (VectorObject*)arg1;
184 if(!BaseMath_ReadCallback(vec))
187 if(QuaternionObject_Check(arg2)){
188 quat = (QuaternionObject*)arg2;
189 if(!BaseMath_ReadCallback(quat))
192 rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
193 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
194 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
195 quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
196 rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
197 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
198 quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
199 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
200 rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
201 quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
202 quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
203 quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
204 return newVectorObject(rot, 3, Py_NEW);
208 PyErr_SetString(PyExc_RuntimeError, "quat_rotation(internal): internal problem rotating vector/point\n");
213 //----------------------------------Mathutils.Rand() --------------------
214 //returns a random number between a high and low value
215 static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args)
217 float high, low, range;
223 if(!PyArg_ParseTuple(args, "|ff", &low, &high)) {
224 PyErr_SetString(PyExc_TypeError, "Mathutils.Rand(): expected nothing or optional (float, float)\n");
228 if((high < low) || (high < 0 && low > 0)) {
229 PyErr_SetString(PyExc_ValueError, "Mathutils.Rand(): high value should be larger than low value\n");
232 //get the random number 0 - 1
237 drand = drand * range;
240 return PyFloat_FromDouble(drand);
242 //----------------------------------VECTOR FUNCTIONS---------------------
243 //----------------------------------Mathutils.AngleBetweenVecs() ---------
244 //calculates the angle between 2 vectors
245 static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
247 VectorObject *vec1 = NULL, *vec2 = NULL;
248 double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
251 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
252 goto AttributeError1; //not vectors
253 if(vec1->size != vec2->size)
254 goto AttributeError1; //bad sizes
256 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
259 //since size is the same....
262 for(x = 0; x < size; x++) {
263 test_v1 += vec1->vec[x] * vec1->vec[x];
264 test_v2 += vec2->vec[x] * vec2->vec[x];
266 if (!test_v1 || !test_v2){
267 goto AttributeError2; //zero-length vector
271 for(x = 0; x < size; x++) {
272 dot += vec1->vec[x] * vec2->vec[x];
274 dot /= (sqrt(test_v1) * sqrt(test_v2));
276 angleRads = (double)saacos(dot);
278 return PyFloat_FromDouble(angleRads * (180/ Py_PI));
281 PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
285 PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n");
288 //----------------------------------Mathutils.MidpointVecs() -------------
289 //calculates the midpoint between 2 vectors
290 static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args)
292 VectorObject *vec1 = NULL, *vec2 = NULL;
296 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) {
297 PyErr_SetString(PyExc_TypeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
300 if(vec1->size != vec2->size) {
301 PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
305 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
308 for(x = 0; x < vec1->size; x++) {
309 vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]);
311 return newVectorObject(vec, vec1->size, Py_NEW);
313 //----------------------------------Mathutils.ProjectVecs() -------------
314 //projects vector 1 onto vector 2
315 static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args)
317 VectorObject *vec1 = NULL, *vec2 = NULL;
319 double dot = 0.0f, dot2 = 0.0f;
322 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) {
323 PyErr_SetString(PyExc_TypeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
326 if(vec1->size != vec2->size) {
327 PyErr_SetString(PyExc_AttributeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
331 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
335 //since they are the same size...
339 for(x = 0; x < size; x++) {
340 dot += vec1->vec[x] * vec2->vec[x];
341 dot2 += vec2->vec[x] * vec2->vec[x];
345 for(x = 0; x < size; x++) {
346 vec[x] = (float)(dot * vec2->vec[x]);
348 return newVectorObject(vec, size, Py_NEW);
350 //----------------------------------MATRIX FUNCTIONS--------------------
351 //----------------------------------Mathutils.RotationMatrix() ----------
352 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
353 //creates a rotation matrix
354 static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
356 VectorObject *vec = NULL;
359 float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f;
360 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
361 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
363 if(!PyArg_ParseTuple(args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) {
364 PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n");
368 /* Clamp to -360:360 */
369 while (angle<-360.0f)
374 if(matSize != 2 && matSize != 3 && matSize != 4) {
375 PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
378 if(matSize == 2 && (axis != NULL || vec != NULL)) {
379 PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n");
382 if((matSize == 3 || matSize == 4) && axis == NULL) {
383 PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n");
387 if(((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) && vec == NULL) {
388 PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n");
394 PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
398 if(!BaseMath_ReadCallback(vec))
403 angle = angle * (float) (Py_PI / 180);
404 if(axis == NULL && matSize == 2) {
406 mat[0] = (float) cos (angle);
407 mat[1] = (float) sin (angle);
408 mat[2] = -((float) sin(angle));
409 mat[3] = (float) cos(angle);
410 } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) {
413 mat[4] = (float) cos(angle);
414 mat[5] = (float) sin(angle);
415 mat[7] = -((float) sin(angle));
416 mat[8] = (float) cos(angle);
417 } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) {
419 mat[0] = (float) cos(angle);
420 mat[2] = -((float) sin(angle));
422 mat[6] = (float) sin(angle);
423 mat[8] = (float) cos(angle);
424 } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) {
426 mat[0] = (float) cos(angle);
427 mat[1] = (float) sin(angle);
428 mat[3] = -((float) sin(angle));
429 mat[4] = (float) cos(angle);
431 } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) {
433 //normalize arbitrary axis
434 norm = (float) sqrt(vec->vec[0] * vec->vec[0] +
435 vec->vec[1] * vec->vec[1] +
436 vec->vec[2] * vec->vec[2]);
441 if (isnan(vec->vec[0]) || isnan(vec->vec[1]) || isnan(vec->vec[2])) {
442 /* zero length vector, return an identity matrix, could also return an error */
443 mat[0]= mat[4] = mat[8] = 1.0f;
446 cosAngle = (float) cos(angle);
447 sinAngle = (float) sin(angle);
448 mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) +
450 mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) +
451 (vec->vec[2] * sinAngle);
452 mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) -
453 (vec->vec[1] * sinAngle);
454 mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) -
455 (vec->vec[2] * sinAngle);
456 mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) +
458 mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) +
459 (vec->vec[0] * sinAngle);
460 mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) +
461 (vec->vec[1] * sinAngle);
462 mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) -
463 (vec->vec[0] * sinAngle);
464 mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) +
468 PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n");
482 //pass to matrix creation
483 return newMatrixObject(mat, matSize, matSize, Py_NEW);
485 //----------------------------------Mathutils.TranslationMatrix() -------
486 //creates a translation matrix
487 static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec)
489 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
490 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
492 if(!VectorObject_Check(vec)) {
493 PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): expected vector\n");
496 if(vec->size != 3 && vec->size != 4) {
497 PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n");
501 if(!BaseMath_ReadCallback(vec))
504 //create a identity matrix and add translation
505 Mat4One((float(*)[4]) mat);
506 mat[12] = vec->vec[0];
507 mat[13] = vec->vec[1];
508 mat[14] = vec->vec[2];
510 return newMatrixObject(mat, 4, 4, Py_NEW);
512 //----------------------------------Mathutils.ScaleMatrix() -------------
513 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
514 //creates a scaling matrix
515 static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
517 VectorObject *vec = NULL;
518 float norm = 0.0f, factor;
520 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
521 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
523 if(!PyArg_ParseTuple(args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) {
524 PyErr_SetString(PyExc_TypeError, "Mathutils.ScaleMatrix(): expected float int and optional vector\n");
527 if(matSize != 2 && matSize != 3 && matSize != 4) {
528 PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
532 if(vec->size > 2 && matSize == 2) {
533 PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n");
537 if(!BaseMath_ReadCallback(vec))
541 if(vec == NULL) { //scaling along axis
550 } else { //scaling in arbitrary direction
551 //normalize arbitrary axis
552 for(x = 0; x < vec->size; x++) {
553 norm += vec->vec[x] * vec->vec[x];
555 norm = (float) sqrt(norm);
556 for(x = 0; x < vec->size; x++) {
560 mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0]));
561 mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
562 mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
563 mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
565 mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0]));
566 mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
567 mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
568 mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
569 mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
570 mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
571 mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
572 mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
573 mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2]));
587 //pass to matrix creation
588 return newMatrixObject(mat, matSize, matSize, Py_NEW);
590 //----------------------------------Mathutils.OrthoProjectionMatrix() ---
591 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
592 //creates an ortho projection matrix
593 static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args)
595 VectorObject *vec = NULL;
599 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
600 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
602 if(!PyArg_ParseTuple(args, "si|O!", &plane, &matSize, &vector_Type, &vec)) {
603 PyErr_SetString(PyExc_TypeError, "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n");
606 if(matSize != 2 && matSize != 3 && matSize != 4) {
607 PyErr_SetString(PyExc_AttributeError,"Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
611 if(vec->size > 2 && matSize == 2) {
612 PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n");
616 if(!BaseMath_ReadCallback(vec))
620 if(vec == NULL) { //ortho projection onto cardinal plane
621 if(((strcmp(plane, "x") == 0)
622 || (strcmp(plane, "X") == 0)) && matSize == 2) {
624 } else if(((strcmp(plane, "y") == 0)
625 || (strcmp(plane, "Y") == 0))
628 } else if(((strcmp(plane, "xy") == 0)
629 || (strcmp(plane, "XY") == 0))
633 } else if(((strcmp(plane, "xz") == 0)
634 || (strcmp(plane, "XZ") == 0))
638 } else if(((strcmp(plane, "yz") == 0)
639 || (strcmp(plane, "YZ") == 0))
644 PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n");
647 } else { //arbitrary plane
648 //normalize arbitrary axis
649 for(x = 0; x < vec->size; x++) {
650 norm += vec->vec[x] * vec->vec[x];
652 norm = (float) sqrt(norm);
653 for(x = 0; x < vec->size; x++) {
656 if(((strcmp(plane, "r") == 0)
657 || (strcmp(plane, "R") == 0)) && matSize == 2) {
658 mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
659 mat[1] = -(vec->vec[0] * vec->vec[1]);
660 mat[2] = -(vec->vec[0] * vec->vec[1]);
661 mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
662 } else if(((strcmp(plane, "r") == 0)
663 || (strcmp(plane, "R") == 0))
665 mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
666 mat[1] = -(vec->vec[0] * vec->vec[1]);
667 mat[2] = -(vec->vec[0] * vec->vec[2]);
668 mat[3] = -(vec->vec[0] * vec->vec[1]);
669 mat[4] = 1 - (vec->vec[1] * vec->vec[1]);
670 mat[5] = -(vec->vec[1] * vec->vec[2]);
671 mat[6] = -(vec->vec[0] * vec->vec[2]);
672 mat[7] = -(vec->vec[1] * vec->vec[2]);
673 mat[8] = 1 - (vec->vec[2] * vec->vec[2]);
675 PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n");
690 //pass to matrix creation
691 return newMatrixObject(mat, matSize, matSize, Py_NEW);
693 //----------------------------------Mathutils.ShearMatrix() -------------
694 //creates a shear matrix
695 static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
700 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
701 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
703 if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) {
704 PyErr_SetString(PyExc_TypeError,"Mathutils.ShearMatrix(): expected string float and int\n");
707 if(matSize != 2 && matSize != 3 && matSize != 4) {
708 PyErr_SetString(PyExc_AttributeError,"Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
712 if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0))
717 } else if(((strcmp(plane, "y") == 0)
718 || (strcmp(plane, "Y") == 0)) && matSize == 2) {
722 } else if(((strcmp(plane, "xy") == 0)
723 || (strcmp(plane, "XY") == 0)) && matSize > 2) {
728 } else if(((strcmp(plane, "xz") == 0)
729 || (strcmp(plane, "XZ") == 0)) && matSize > 2) {
735 } else if(((strcmp(plane, "yz") == 0)
736 || (strcmp(plane, "YZ") == 0)) && matSize > 2) {
743 PyErr_SetString(PyExc_AttributeError, "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n");
757 //pass to matrix creation
758 return newMatrixObject(mat, matSize, matSize, Py_NEW);
760 //----------------------------------QUATERNION FUNCTIONS-----------------
762 //----------------------------------Mathutils.DifferenceQuats() ---------
763 //returns the difference between 2 quaternions
764 static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args)
766 QuaternionObject *quatU = NULL, *quatV = NULL;
767 float quat[4], tempQuat[4];
771 if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, &quaternion_Type, &quatV)) {
772 PyErr_SetString(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types");
776 if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV))
779 tempQuat[0] = quatU->quat[0];
780 tempQuat[1] = -quatU->quat[1];
781 tempQuat[2] = -quatU->quat[2];
782 tempQuat[3] = -quatU->quat[3];
784 dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] +
785 tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]);
787 for(x = 0; x < 4; x++) {
788 tempQuat[x] /= (float)(dot * dot);
790 QuatMul(quat, tempQuat, quatV->quat);
791 return newQuaternionObject(quat, Py_NEW);
793 //----------------------------------Mathutils.Slerp() ------------------
794 //attemps to interpolate 2 quaternions and return the result
795 static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args)
797 QuaternionObject *quatU = NULL, *quatV = NULL;
798 float quat[4], quat_u[4], quat_v[4], param;
799 double x, y, dot, sinT, angle, IsinT;
802 if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, &quatU, &quaternion_Type, &quatV, ¶m)) {
803 PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float");
807 if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV))
810 if(param > 1.0f || param < 0.0f) {
811 PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
816 for(z = 0; z < 4; z++){
817 quat_u[z] = quatU->quat[z];
818 quat_v[z] = quatV->quat[z];
822 dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] +
823 quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3];
825 //if negative negate a quat (shortest arc)
827 quat_v[0] = -quat_v[0];
828 quat_v[1] = -quat_v[1];
829 quat_v[2] = -quat_v[2];
830 quat_v[3] = -quat_v[3];
833 if(dot > .99999f) { //very close
837 //calculate sin of angle
838 sinT = sqrt(1.0f - (dot * dot));
840 angle = atan2(sinT, dot);
841 //caluculate inverse of sin(theta)
843 x = sin((1.0f - param) * angle) * IsinT;
844 y = sin(param * angle) * IsinT;
847 quat[0] = (float)(quat_u[0] * x + quat_v[0] * y);
848 quat[1] = (float)(quat_u[1] * x + quat_v[1] * y);
849 quat[2] = (float)(quat_u[2] * x + quat_v[2] * y);
850 quat[3] = (float)(quat_u[3] * x + quat_v[3] * y);
852 return newQuaternionObject(quat, Py_NEW);
854 //----------------------------------EULER FUNCTIONS----------------------
855 //---------------------------------INTERSECTION FUNCTIONS--------------------
856 //----------------------------------Mathutils.Intersect() -------------------
857 static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
859 VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
860 float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
861 float det, inv_det, u, v, t;
864 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)) {
865 PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" );
868 if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
869 PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n");
873 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off))
876 VECCOPY(v1, vec1->vec);
877 VECCOPY(v2, vec2->vec);
878 VECCOPY(v3, vec3->vec);
880 VECCOPY(dir, ray->vec);
883 VECCOPY(orig, ray_off->vec);
885 /* find vectors for two edges sharing v1 */
889 /* begin calculating determinant - also used to calculated U parameter */
890 Crossf(pvec, dir, e2);
892 /* if determinant is near zero, ray lies in plane of triangle */
893 det = Inpf(e1, pvec);
895 if (det > -0.000001 && det < 0.000001) {
899 inv_det = 1.0f / det;
901 /* calculate distance from v1 to ray origin */
902 VecSubf(tvec, orig, v1);
904 /* calculate U parameter and test bounds */
905 u = Inpf(tvec, pvec) * inv_det;
906 if (clip && (u < 0.0f || u > 1.0f)) {
910 /* prepare to test the V parameter */
911 Crossf(qvec, tvec, e1);
913 /* calculate V parameter and test bounds */
914 v = Inpf(dir, qvec) * inv_det;
916 if (clip && (v < 0.0f || u + v > 1.0f)) {
920 /* calculate t, ray intersects triangle */
921 t = Inpf(e2, qvec) * inv_det;
924 VecAddf(pvec, orig, dir);
926 return newVectorObject(pvec, 3, Py_NEW);
928 //----------------------------------Mathutils.LineIntersect() -------------------
929 /* Line-Line intersection using algorithm from mathworld.wolfram.com */
930 static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args )
933 VectorObject *vec1, *vec2, *vec3, *vec4;
934 float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
936 if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
937 PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
940 if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size) {
941 PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
945 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
948 if( vec1->size == 3 || vec1->size == 2) {
951 if (vec1->size == 3) {
952 VECCOPY(v1, vec1->vec);
953 VECCOPY(v2, vec2->vec);
954 VECCOPY(v3, vec3->vec);
955 VECCOPY(v4, vec4->vec);
958 v1[0] = vec1->vec[0];
959 v1[1] = vec1->vec[1];
962 v2[0] = vec2->vec[0];
963 v2[1] = vec2->vec[1];
966 v3[0] = vec3->vec[0];
967 v3[1] = vec3->vec[1];
970 v4[0] = vec4->vec[0];
971 v4[1] = vec4->vec[1];
975 result = LineIntersectLine(v1, v2, v3, v4, i1, i2);
982 tuple = PyTuple_New( 2 );
983 PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW) );
984 PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW) );
989 PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" );
996 //---------------------------------NORMALS FUNCTIONS--------------------
997 //----------------------------------Mathutils.QuadNormal() -------------------
998 static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
1004 float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3];
1006 if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
1007 PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
1010 if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
1011 PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
1014 if( vec1->size != 3 ) {
1015 PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
1019 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
1022 VECCOPY(v1, vec1->vec);
1023 VECCOPY(v2, vec2->vec);
1024 VECCOPY(v3, vec3->vec);
1025 VECCOPY(v4, vec4->vec);
1027 /* find vectors for two edges sharing v2 */
1028 VecSubf(e1, v1, v2);
1029 VecSubf(e2, v3, v2);
1034 /* find vectors for two edges sharing v4 */
1035 VecSubf(e1, v3, v4);
1036 VecSubf(e2, v1, v4);
1041 /* adding and averaging the normals of both triangles */
1042 VecAddf(n1, n2, n1);
1045 return newVectorObject(n1, 3, Py_NEW);
1048 //----------------------------Mathutils.TriangleNormal() -------------------
1049 static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args )
1051 VectorObject *vec1, *vec2, *vec3;
1052 float v1[3], v2[3], v3[3], e1[3], e2[3], n[3];
1054 if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) {
1055 PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
1058 if( vec1->size != vec2->size || vec1->size != vec3->size ) {
1059 PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
1062 if( vec1->size != 3 ) {
1063 PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
1067 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
1070 VECCOPY(v1, vec1->vec);
1071 VECCOPY(v2, vec2->vec);
1072 VECCOPY(v3, vec3->vec);
1074 /* find vectors for two edges sharing v2 */
1075 VecSubf(e1, v1, v2);
1076 VecSubf(e2, v3, v2);
1081 return newVectorObject(n, 3, Py_NEW);
1084 //--------------------------------- AREA FUNCTIONS--------------------
1085 //----------------------------------Mathutils.TriangleArea() -------------------
1086 static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args )
1088 VectorObject *vec1, *vec2, *vec3;
1089 float v1[3], v2[3], v3[3];
1091 if( !PyArg_ParseTuple
1092 ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
1093 , &vector_Type, &vec3 ) ) {
1094 PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n");
1097 if( vec1->size != vec2->size || vec1->size != vec3->size ) {
1098 PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
1102 if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
1105 if (vec1->size == 3) {
1106 VECCOPY(v1, vec1->vec);
1107 VECCOPY(v2, vec2->vec);
1108 VECCOPY(v3, vec3->vec);
1110 return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3) );
1112 else if (vec1->size == 2) {
1113 v1[0] = vec1->vec[0];
1114 v1[1] = vec1->vec[1];
1116 v2[0] = vec2->vec[0];
1117 v2[1] = vec2->vec[1];
1119 v3[0] = vec3->vec[0];
1120 v3[1] = vec3->vec[1];
1122 return PyFloat_FromDouble( AreaF2Dfl(v1, v2, v3) );
1125 PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" );
1130 /* Utility functions */
1132 /*---------------------- EXPP_FloatsAreEqual -------------------------
1133 Floating point comparisons
1134 floatStep = number of representable floats allowable in between
1135 float A and float B to be considered equal. */
1136 int EXPP_FloatsAreEqual(float A, float B, int floatSteps)
1139 assert(floatSteps > 0 && floatSteps < (4 * 1024 * 1024));
1147 if (delta <= floatSteps)
1151 /*---------------------- EXPP_VectorsAreEqual -------------------------
1152 Builds on EXPP_FloatsAreEqual to test vectors */
1153 int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
1156 for (x=0; x< size; x++){
1157 if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
1164 /* Mathutils Callbacks */
1166 /* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
1167 Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
1169 int Mathutils_RegisterCallback(Mathutils_Callback *cb)
1173 /* find the first free slot */
1174 for(i= 0; mathutils_callbacks[i]; i++) {
1175 if(mathutils_callbacks[i]==cb) /* alredy registered? */
1179 mathutils_callbacks[i] = cb;
1183 /* use macros to check for NULL */
1184 int _BaseMathObject_ReadCallback(BaseMathObject *self)
1186 Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
1187 if(cb->get(self->cb_user, self->cb_subtype, self->data))
1190 PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
1194 int _BaseMathObject_WriteCallback(BaseMathObject *self)
1196 Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
1197 if(cb->set(self->cb_user, self->cb_subtype, self->data))
1200 PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
1204 int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
1206 Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
1207 if(cb->get_index(self->cb_user, self->cb_subtype, self->data, index))
1210 PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
1214 int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
1216 Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
1217 if(cb->set_index(self->cb_user, self->cb_subtype, self->data, index))
1220 PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
1224 /* BaseMathObject generic functions for all mathutils types */
1225 PyObject *BaseMathObject_getOwner( BaseMathObject * self, void *type )
1227 PyObject *ret= self->cb_user ? self->cb_user : Py_None;
1232 PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void *type )
1234 PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0);
1237 void BaseMathObject_dealloc(BaseMathObject * self)
1239 /* only free non wrapped */
1240 if(self->wrapped != Py_WRAP)
1241 PyMem_Free(self->data);
1243 Py_XDECREF(self->cb_user);