== Sequencer ==
[plumiferos.git] / source / blender / python / api2_2x / Mathutils.c
blob55762fbd355b641d57e533439bd5958a5664bb22
1 /*
2 * $Id: Mathutils.c 10801 2007-05-28 21:53:49Z campbellbarton $
4 * ***** BEGIN GPL/BL DUAL 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. The Blender
10 * Foundation also sells licenses for use in proprietary software under
11 * the Blender License. See http://www.blender.org/BL/ for information
12 * about this.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * This is a new part of Blender.
28 * Contributor(s): Joseph Gilbert, Campbell Barton
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
33 #include "Mathutils.h"
35 #include "BLI_arithb.h"
36 #include "PIL_time.h"
37 #include "BLI_rand.h"
38 #include "BKE_utildefines.h"
40 #include "gen_utils.h"
42 //-------------------------DOC STRINGS ---------------------------
43 static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
44 static char M_Mathutils_Vector_doc[] = "() - create a new vector object from a list of floats";
45 static char M_Mathutils_Matrix_doc[] = "() - create a new matrix object from a list of floats";
46 static char M_Mathutils_Quaternion_doc[] = "() - create a quaternion from a list or an axis of rotation and an angle";
47 static char M_Mathutils_Euler_doc[] = "() - create and return a new euler object";
48 static char M_Mathutils_Rand_doc[] = "() - return a random number";
49 static char M_Mathutils_CrossVecs_doc[] = "() - returns a vector perpedicular to the 2 vectors crossed";
50 static char M_Mathutils_CopyVec_doc[] = "() - create a copy of vector";
51 static char M_Mathutils_DotVecs_doc[] = "() - return the dot product of two vectors";
52 static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees";
53 static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors";
54 static char M_Mathutils_MatMultVec_doc[] = "() - multiplies a matrix by a column vector";
55 static char M_Mathutils_VecMultMat_doc[] = "() - multiplies a row vector by a matrix";
56 static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB";
57 static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation";
58 static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor";
59 static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane";
60 static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor";
61 static char M_Mathutils_CopyMat_doc[] = "() - create a copy of a matrix";
62 static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector";
63 static char M_Mathutils_CopyQuat_doc[] = "() - copy quatB to quatA";
64 static char M_Mathutils_CopyEuler_doc[] = "() - copy eulB to eultA";
65 static char M_Mathutils_CrossQuats_doc[] = "() - return the mutliplication of two quaternions";
66 static char M_Mathutils_DotQuats_doc[] = "() - return the dot product of two quaternions";
67 static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions";
68 static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats";
69 static char M_Mathutils_RotateEuler_doc[] = "() - rotate euler by an axis and angle";
70 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";
71 static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined";
72 static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined";
73 static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined";
74 static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other";
75 static char M_Mathutils_Point_doc[] = "Creates a 2d or 3d point object";
76 //-----------------------METHOD DEFINITIONS ----------------------
77 struct PyMethodDef M_Mathutils_methods[] = {
78 {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc},
79 {"Vector", (PyCFunction) M_Mathutils_Vector, METH_VARARGS, M_Mathutils_Vector_doc},
80 {"CrossVecs", (PyCFunction) M_Mathutils_CrossVecs, METH_VARARGS, M_Mathutils_CrossVecs_doc},
81 {"DotVecs", (PyCFunction) M_Mathutils_DotVecs, METH_VARARGS, M_Mathutils_DotVecs_doc},
82 {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc},
83 {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc},
84 {"VecMultMat", (PyCFunction) M_Mathutils_VecMultMat, METH_VARARGS, M_Mathutils_VecMultMat_doc},
85 {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc},
86 {"CopyVec", (PyCFunction) M_Mathutils_CopyVec, METH_VARARGS, M_Mathutils_CopyVec_doc},
87 {"Matrix", (PyCFunction) M_Mathutils_Matrix, METH_VARARGS, M_Mathutils_Matrix_doc},
88 {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc},
89 {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc},
90 {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc},
91 {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc},
92 {"CopyMat", (PyCFunction) M_Mathutils_CopyMat, METH_VARARGS, M_Mathutils_CopyMat_doc},
93 {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc},
94 {"MatMultVec", (PyCFunction) M_Mathutils_MatMultVec, METH_VARARGS, M_Mathutils_MatMultVec_doc},
95 {"Quaternion", (PyCFunction) M_Mathutils_Quaternion, METH_VARARGS, M_Mathutils_Quaternion_doc},
96 {"CopyQuat", (PyCFunction) M_Mathutils_CopyQuat, METH_VARARGS, M_Mathutils_CopyQuat_doc},
97 {"CrossQuats", (PyCFunction) M_Mathutils_CrossQuats, METH_VARARGS, M_Mathutils_CrossQuats_doc},
98 {"DotQuats", (PyCFunction) M_Mathutils_DotQuats, METH_VARARGS, M_Mathutils_DotQuats_doc},
99 {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc},
100 {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc},
101 {"Euler", (PyCFunction) M_Mathutils_Euler, METH_VARARGS, M_Mathutils_Euler_doc},
102 {"CopyEuler", (PyCFunction) M_Mathutils_CopyEuler, METH_VARARGS, M_Mathutils_CopyEuler_doc},
103 {"RotateEuler", (PyCFunction) M_Mathutils_RotateEuler, METH_VARARGS, M_Mathutils_RotateEuler_doc},
104 {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc},
105 {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc},
106 {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc},
107 {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc},
108 {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc},
109 {"Point", (PyCFunction) M_Mathutils_Point, METH_VARARGS, M_Mathutils_Point_doc},
110 {NULL, NULL, 0, NULL}
112 //----------------------------MODULE INIT-------------------------
113 PyObject *Mathutils_Init(void)
115 PyObject *submodule;
117 //seed the generator for the rand function
118 BLI_srand((unsigned int) (PIL_check_seconds_timer() *
119 0x7FFFFFFF));
121 /* needed for getseters */
122 if( PyType_Ready( &vector_Type ) < 0 )
123 return NULL;
124 if( PyType_Ready( &matrix_Type ) < 0 )
125 return NULL;
126 if( PyType_Ready( &euler_Type ) < 0 )
127 return NULL;
128 if( PyType_Ready( &quaternion_Type ) < 0 )
129 return NULL;
131 submodule = Py_InitModule3("Blender.Mathutils",
132 M_Mathutils_methods, M_Mathutils_doc);
133 return (submodule);
135 //-----------------------------METHODS----------------------------
136 //----------------column_vector_multiplication (internal)---------
137 //COLUMN VECTOR Multiplication (Matrix X Vector)
138 // [1][2][3] [a]
139 // [4][5][6] * [b]
140 // [7][8][9] [c]
141 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
142 PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec)
144 float vecNew[4], vecCopy[4];
145 double dot = 0.0f;
146 int x, y, z = 0;
148 if(mat->rowSize != vec->size){
149 if(mat->rowSize == 4 && vec->size != 3){
150 return EXPP_ReturnPyObjError(PyExc_AttributeError,
151 "matrix * vector: matrix row size and vector size must be the same");
152 }else{
153 vecCopy[3] = 1.0f;
157 for(x = 0; x < vec->size; x++){
158 vecCopy[x] = vec->vec[x];
161 for(x = 0; x < mat->rowSize; x++) {
162 for(y = 0; y < mat->colSize; y++) {
163 dot += mat->matrix[x][y] * vecCopy[y];
165 vecNew[z++] = (float)dot;
166 dot = 0.0f;
168 return newVectorObject(vecNew, vec->size, Py_NEW);
170 //This is a helper for point/matrix translation
172 PyObject *column_point_multiplication(MatrixObject * mat, PointObject* pt)
174 float ptNew[4], ptCopy[4];
175 double dot = 0.0f;
176 int x, y, z = 0;
178 if(mat->rowSize != pt->size){
179 if(mat->rowSize == 4 && pt->size != 3){
180 return EXPP_ReturnPyObjError(PyExc_AttributeError,
181 "matrix * point: matrix row size and point size must be the same\n");
182 }else{
183 ptCopy[3] = 0.0f;
187 for(x = 0; x < pt->size; x++){
188 ptCopy[x] = pt->coord[x];
191 for(x = 0; x < mat->rowSize; x++) {
192 for(y = 0; y < mat->colSize; y++) {
193 dot += mat->matrix[x][y] * ptCopy[y];
195 ptNew[z++] = (float)dot;
196 dot = 0.0f;
198 return newPointObject(ptNew, pt->size, Py_NEW);
200 //-----------------row_vector_multiplication (internal)-----------
201 //ROW VECTOR Multiplication - Vector X Matrix
202 //[x][y][z] * [1][2][3]
203 // [4][5][6]
204 // [7][8][9]
205 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
206 PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat)
208 float vecNew[4], vecCopy[4];
209 double dot = 0.0f;
210 int x, y, z = 0, vec_size = vec->size;
212 if(mat->colSize != vec_size){
213 if(mat->rowSize == 4 && vec_size != 3){
214 return EXPP_ReturnPyObjError(PyExc_AttributeError,
215 "vector * matrix: matrix column size and the vector size must be the same");
216 }else{
217 vecCopy[3] = 1.0f;
221 for(x = 0; x < vec_size; x++){
222 vecCopy[x] = vec->vec[x];
225 //muliplication
226 for(x = 0; x < mat->colSize; x++) {
227 for(y = 0; y < mat->rowSize; y++) {
228 dot += mat->matrix[y][x] * vecCopy[y];
230 vecNew[z++] = (float)dot;
231 dot = 0.0f;
233 return newVectorObject(vecNew, vec_size, Py_NEW);
235 //This is a helper for the point class
236 PyObject *row_point_multiplication(PointObject* pt, MatrixObject * mat)
238 float ptNew[4], ptCopy[4];
239 double dot = 0.0f;
240 int x, y, z = 0, size;
242 if(mat->colSize != pt->size){
243 if(mat->rowSize == 4 && pt->size != 3){
244 return EXPP_ReturnPyObjError(PyExc_AttributeError,
245 "point * matrix: matrix column size and the point size must be the same\n");
246 }else{
247 ptCopy[3] = 0.0f;
250 size = pt->size;
251 for(x = 0; x < pt->size; x++){
252 ptCopy[x] = pt->coord[x];
255 //muliplication
256 for(x = 0; x < mat->colSize; x++) {
257 for(y = 0; y < mat->rowSize; y++) {
258 dot += mat->matrix[y][x] * ptCopy[y];
260 ptNew[z++] = (float)dot;
261 dot = 0.0f;
263 return newPointObject(ptNew, size, Py_NEW);
265 //-----------------quat_rotation (internal)-----------
266 //This function multiplies a vector/point * quat or vice versa
267 //to rotate the point/vector by the quaternion
268 //arguments should all be 3D
269 PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
271 float rot[3];
272 QuaternionObject *quat = NULL;
273 VectorObject *vec = NULL;
274 PointObject *pt = NULL;
276 if(QuaternionObject_Check(arg1)){
277 quat = (QuaternionObject*)arg1;
278 if(VectorObject_Check(arg2)){
279 vec = (VectorObject*)arg2;
280 rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
281 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
282 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
283 quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
284 rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
285 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
286 quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
287 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
288 rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
289 quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
290 quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
291 quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
292 return newVectorObject(rot, 3, Py_NEW);
293 }else if(PointObject_Check(arg2)){
294 pt = (PointObject*)arg2;
295 rot[0] = quat->quat[0]*quat->quat[0]*pt->coord[0] + 2*quat->quat[2]*quat->quat[0]*pt->coord[2] -
296 2*quat->quat[3]*quat->quat[0]*pt->coord[1] + quat->quat[1]*quat->quat[1]*pt->coord[0] +
297 2*quat->quat[2]*quat->quat[1]*pt->coord[1] + 2*quat->quat[3]*quat->quat[1]*pt->coord[2] -
298 quat->quat[3]*quat->quat[3]*pt->coord[0] - quat->quat[2]*quat->quat[2]*pt->coord[0];
299 rot[1] = 2*quat->quat[1]*quat->quat[2]*pt->coord[0] + quat->quat[2]*quat->quat[2]*pt->coord[1] +
300 2*quat->quat[3]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[3]*pt->coord[0] -
301 quat->quat[3]*quat->quat[3]*pt->coord[1] + quat->quat[0]*quat->quat[0]*pt->coord[1] -
302 2*quat->quat[1]*quat->quat[0]*pt->coord[2] - quat->quat[1]*quat->quat[1]*pt->coord[1];
303 rot[2] = 2*quat->quat[1]*quat->quat[3]*pt->coord[0] + 2*quat->quat[2]*quat->quat[3]*pt->coord[1] +
304 quat->quat[3]*quat->quat[3]*pt->coord[2] - 2*quat->quat[0]*quat->quat[2]*pt->coord[0] -
305 quat->quat[2]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[1]*pt->coord[1] -
306 quat->quat[1]*quat->quat[1]*pt->coord[2] + quat->quat[0]*quat->quat[0]*pt->coord[2];
307 return newPointObject(rot, 3, Py_NEW);
309 }else if(VectorObject_Check(arg1)){
310 vec = (VectorObject*)arg1;
311 if(QuaternionObject_Check(arg2)){
312 quat = (QuaternionObject*)arg2;
313 rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
314 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
315 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
316 quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
317 rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
318 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
319 quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
320 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
321 rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
322 quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
323 quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
324 quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
325 return newVectorObject(rot, 3, Py_NEW);
327 }else if(PointObject_Check(arg1)){
328 pt = (PointObject*)arg1;
329 if(QuaternionObject_Check(arg2)){
330 quat = (QuaternionObject*)arg2;
331 rot[0] = quat->quat[0]*quat->quat[0]*pt->coord[0] + 2*quat->quat[2]*quat->quat[0]*pt->coord[2] -
332 2*quat->quat[3]*quat->quat[0]*pt->coord[1] + quat->quat[1]*quat->quat[1]*pt->coord[0] +
333 2*quat->quat[2]*quat->quat[1]*pt->coord[1] + 2*quat->quat[3]*quat->quat[1]*pt->coord[2] -
334 quat->quat[3]*quat->quat[3]*pt->coord[0] - quat->quat[2]*quat->quat[2]*pt->coord[0];
335 rot[1] = 2*quat->quat[1]*quat->quat[2]*pt->coord[0] + quat->quat[2]*quat->quat[2]*pt->coord[1] +
336 2*quat->quat[3]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[3]*pt->coord[0] -
337 quat->quat[3]*quat->quat[3]*pt->coord[1] + quat->quat[0]*quat->quat[0]*pt->coord[1] -
338 2*quat->quat[1]*quat->quat[0]*pt->coord[2] - quat->quat[1]*quat->quat[1]*pt->coord[1];
339 rot[2] = 2*quat->quat[1]*quat->quat[3]*pt->coord[0] + 2*quat->quat[2]*quat->quat[3]*pt->coord[1] +
340 quat->quat[3]*quat->quat[3]*pt->coord[2] - 2*quat->quat[0]*quat->quat[2]*pt->coord[0] -
341 quat->quat[2]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[1]*pt->coord[1] -
342 quat->quat[1]*quat->quat[1]*pt->coord[2] + quat->quat[0]*quat->quat[0]*pt->coord[2];
343 return newPointObject(rot, 3, Py_NEW);
347 return (EXPP_ReturnPyObjError(PyExc_RuntimeError,
348 "quat_rotation(internal): internal problem rotating vector/point\n"));
351 //----------------------------------Mathutils.Rand() --------------------
352 //returns a random number between a high and low value
353 PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args)
355 float high, low, range;
356 double rand;
357 //initializers
358 high = 1.0;
359 low = 0.0;
361 if(!PyArg_ParseTuple(args, "|ff", &low, &high))
362 return (EXPP_ReturnPyObjError(PyExc_TypeError,
363 "Mathutils.Rand(): expected nothing or optional (float, float)\n"));
365 if((high < low) || (high < 0 && low > 0))
366 return (EXPP_ReturnPyObjError(PyExc_ValueError,
367 "Mathutils.Rand(): high value should be larger than low value\n"));
369 //get the random number 0 - 1
370 rand = BLI_drand();
372 //set it to range
373 range = high - low;
374 rand = rand * range;
375 rand = rand + low;
377 return PyFloat_FromDouble(rand);
379 //----------------------------------VECTOR FUNCTIONS---------------------
380 //----------------------------------Mathutils.Vector() ------------------
381 // Supports 2D, 3D, and 4D vector objects both int and float values
382 // accepted. Mixed float and int values accepted. Ints are parsed to float
383 PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args)
385 PyObject *listObject = NULL;
386 int size, i;
387 float vec[4];
388 PyObject *v, *f;
390 size = PySequence_Length(args);
391 if (size == 1) {
392 listObject = PySequence_GetItem(args, 0);
393 if (PySequence_Check(listObject)) {
394 size = PySequence_Length(listObject);
395 } else { // Single argument was not a sequence
396 Py_XDECREF(listObject);
397 return EXPP_ReturnPyObjError(PyExc_TypeError,
398 "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
400 } else if (size == 0) {
401 //returns a new empty 3d vector
402 return newVectorObject(NULL, 3, Py_NEW);
403 } else {
404 listObject = EXPP_incr_ret(args);
407 if (size<2 || size>4) { // Invalid vector size
408 Py_XDECREF(listObject);
409 return EXPP_ReturnPyObjError(PyExc_AttributeError,
410 "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
413 for (i=0; i<size; i++) {
414 v=PySequence_GetItem(listObject, i);
415 if (v==NULL) { // Failed to read sequence
416 Py_XDECREF(listObject);
417 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
418 "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
421 f=PyNumber_Float(v);
422 if(f==NULL) { // parsed item not a number
423 Py_DECREF(v);
424 Py_XDECREF(listObject);
425 return EXPP_ReturnPyObjError(PyExc_TypeError,
426 "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
429 vec[i]=(float)PyFloat_AS_DOUBLE(f);
430 EXPP_decr2(f,v);
432 Py_DECREF(listObject);
433 return newVectorObject(vec, size, Py_NEW);
435 //----------------------------------Mathutils.CrossVecs() ---------------
436 //finds perpendicular vector - only 3D is supported
437 PyObject *M_Mathutils_CrossVecs(PyObject * self, PyObject * args)
439 PyObject *vecCross = NULL;
440 VectorObject *vec1 = NULL, *vec2 = NULL;
442 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
443 return EXPP_ReturnPyObjError(PyExc_TypeError,
444 "Mathutils.CrossVecs(): expects (2) 3D vector objects\n");
445 if(vec1->size != 3 || vec2->size != 3)
446 return EXPP_ReturnPyObjError(PyExc_AttributeError,
447 "Mathutils.CrossVecs(): expects (2) 3D vector objects\n");
449 vecCross = newVectorObject(NULL, 3, Py_NEW);
450 Crossf(((VectorObject*)vecCross)->vec, vec1->vec, vec2->vec);
451 return vecCross;
453 //----------------------------------Mathutils.DotVec() -------------------
454 //calculates the dot product of two vectors
455 PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args)
457 VectorObject *vec1 = NULL, *vec2 = NULL;
458 double dot = 0.0f;
459 int x;
461 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
462 return EXPP_ReturnPyObjError(PyExc_TypeError,
463 "Mathutils.DotVec(): expects (2) vector objects of the same size\n");
464 if(vec1->size != vec2->size)
465 return EXPP_ReturnPyObjError(PyExc_AttributeError,
466 "Mathutils.DotVec(): expects (2) vector objects of the same size\n");
468 for(x = 0; x < vec1->size; x++) {
469 dot += vec1->vec[x] * vec2->vec[x];
471 return PyFloat_FromDouble(dot);
473 //----------------------------------Mathutils.AngleBetweenVecs() ---------
474 //calculates the angle between 2 vectors
475 PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
477 VectorObject *vec1 = NULL, *vec2 = NULL;
478 double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
479 int x, size;
481 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
482 goto AttributeError1; //not vectors
483 if(vec1->size != vec2->size)
484 goto AttributeError1; //bad sizes
486 //since size is the same....
487 size = vec1->size;
489 for(x = 0; x < size; x++) {
490 test_v1 += vec1->vec[x] * vec1->vec[x];
491 test_v2 += vec2->vec[x] * vec2->vec[x];
493 if (!test_v1 || !test_v2){
494 goto AttributeError2; //zero-length vector
497 //dot product
498 for(x = 0; x < size; x++) {
499 dot += vec1->vec[x] * vec2->vec[x];
501 dot /= (sqrt(test_v1) * sqrt(test_v2));
503 if (dot < -1.0f || dot > 1.0f) {
504 CLAMP(dot,-1.0f,1.0f);
506 angleRads = (double)acos(dot);
508 return PyFloat_FromDouble(angleRads * (180/ Py_PI));
510 AttributeError1:
511 return EXPP_ReturnPyObjError(PyExc_AttributeError,
512 "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
514 AttributeError2:
515 return EXPP_ReturnPyObjError(PyExc_AttributeError,
516 "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n");
518 //----------------------------------Mathutils.MidpointVecs() -------------
519 //calculates the midpoint between 2 vectors
520 PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args)
522 VectorObject *vec1 = NULL, *vec2 = NULL;
523 float vec[4];
524 int x;
526 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
527 return EXPP_ReturnPyObjError(PyExc_TypeError,
528 "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
529 if(vec1->size != vec2->size)
530 return EXPP_ReturnPyObjError(PyExc_AttributeError,
531 "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
533 for(x = 0; x < vec1->size; x++) {
534 vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]);
536 return newVectorObject(vec, vec1->size, Py_NEW);
538 //----------------------------------Mathutils.ProjectVecs() -------------
539 //projects vector 1 onto vector 2
540 PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args)
542 VectorObject *vec1 = NULL, *vec2 = NULL;
543 float vec[4];
544 double dot = 0.0f, dot2 = 0.0f;
545 int x, size;
547 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
548 return EXPP_ReturnPyObjError(PyExc_TypeError,
549 "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
550 if(vec1->size != vec2->size)
551 return EXPP_ReturnPyObjError(PyExc_AttributeError,
552 "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
554 //since they are the same size...
555 size = vec1->size;
557 //get dot products
558 for(x = 0; x < size; x++) {
559 dot += vec1->vec[x] * vec2->vec[x];
560 dot2 += vec2->vec[x] * vec2->vec[x];
562 //projection
563 dot /= dot2;
564 for(x = 0; x < size; x++) {
565 vec[x] = (float)(dot * vec2->vec[x]);
567 return newVectorObject(vec, size, Py_NEW);
569 //----------------------------------MATRIX FUNCTIONS--------------------
570 //----------------------------------Mathutils.Matrix() -----------------
571 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
572 //create a new matrix type
573 PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args)
575 PyObject *listObject = NULL;
576 PyObject *argObject, *m, *s, *f;
577 MatrixObject *mat;
578 int argSize, seqSize = 0, i, j;
579 float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
580 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
582 argSize = PySequence_Length(args);
583 if(argSize > 4){ //bad arg nums
584 return EXPP_ReturnPyObjError(PyExc_AttributeError,
585 "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
586 } else if (argSize == 0) { //return empty 4D matrix
587 return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW);
588 }else if (argSize == 1){
589 //copy constructor for matrix objects
590 argObject = PySequence_GetItem(args, 0);
591 if(MatrixObject_Check(argObject)){
592 mat = (MatrixObject*)argObject;
594 argSize = mat->rowSize; //rows
595 seqSize = mat->colSize; //col
596 for(i = 0; i < (seqSize * argSize); i++){
597 matrix[i] = mat->contigPtr[i];
600 Py_DECREF(argObject);
601 }else{ //2-4 arguments (all seqs? all same size?)
602 for(i =0; i < argSize; i++){
603 argObject = PySequence_GetItem(args, i);
604 if (PySequence_Check(argObject)) { //seq?
605 if(seqSize){ //0 at first
606 if(PySequence_Length(argObject) != seqSize){ //seq size not same
607 Py_DECREF(argObject);
608 return EXPP_ReturnPyObjError(PyExc_AttributeError,
609 "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
612 seqSize = PySequence_Length(argObject);
613 }else{ //arg not a sequence
614 Py_XDECREF(argObject);
615 return EXPP_ReturnPyObjError(PyExc_TypeError,
616 "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
618 Py_DECREF(argObject);
620 //all is well... let's continue parsing
621 listObject = args;
622 for (i = 0; i < argSize; i++){
623 m = PySequence_GetItem(listObject, i);
624 if (m == NULL) { // Failed to read sequence
625 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
626 "Mathutils.Matrix(): failed to parse arguments...\n");
629 for (j = 0; j < seqSize; j++) {
630 s = PySequence_GetItem(m, j);
631 if (s == NULL) { // Failed to read sequence
632 Py_DECREF(m);
633 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
634 "Mathutils.Matrix(): failed to parse arguments...\n");
637 f = PyNumber_Float(s);
638 if(f == NULL) { // parsed item is not a number
639 EXPP_decr2(m,s);
640 return EXPP_ReturnPyObjError(PyExc_AttributeError,
641 "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
644 matrix[(seqSize*i)+j]=(float)PyFloat_AS_DOUBLE(f);
645 EXPP_decr2(f,s);
647 Py_DECREF(m);
650 return newMatrixObject(matrix, argSize, seqSize, Py_NEW);
652 //----------------------------------Mathutils.RotationMatrix() ----------
653 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
654 //creates a rotation matrix
655 PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
657 VectorObject *vec = NULL;
658 char *axis = NULL;
659 int matSize;
660 float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f;
661 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
662 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
664 if(!PyArg_ParseTuple
665 (args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) {
666 return EXPP_ReturnPyObjError (PyExc_TypeError,
667 "Mathutils.RotationMatrix(): expected float int and optional string and vector\n");
670 /* Clamp to -360:360 */
671 while (angle<-360.0f)
672 angle+=360.0;
673 while (angle>360.0f)
674 angle-=360.0;
676 if(matSize != 2 && matSize != 3 && matSize != 4)
677 return EXPP_ReturnPyObjError(PyExc_AttributeError,
678 "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
679 if(matSize == 2 && (axis != NULL || vec != NULL))
680 return EXPP_ReturnPyObjError(PyExc_AttributeError,
681 "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n");
682 if((matSize == 3 || matSize == 4) && axis == NULL)
683 return EXPP_ReturnPyObjError(PyExc_AttributeError,
684 "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n");
685 if(axis) {
686 if(((strcmp(axis, "r") == 0) ||
687 (strcmp(axis, "R") == 0)) && vec == NULL)
688 return EXPP_ReturnPyObjError(PyExc_AttributeError,
689 "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n");
691 if(vec) {
692 if(vec->size != 3)
693 return EXPP_ReturnPyObjError(PyExc_AttributeError,
694 "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
696 //convert to radians
697 angle = angle * (float) (Py_PI / 180);
698 if(axis == NULL && matSize == 2) {
699 //2D rotation matrix
700 mat[0] = (float) cos (angle);
701 mat[1] = (float) sin (angle);
702 mat[2] = -((float) sin(angle));
703 mat[3] = (float) cos(angle);
704 } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) {
705 //rotation around X
706 mat[0] = 1.0f;
707 mat[4] = (float) cos(angle);
708 mat[5] = (float) sin(angle);
709 mat[7] = -((float) sin(angle));
710 mat[8] = (float) cos(angle);
711 } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) {
712 //rotation around Y
713 mat[0] = (float) cos(angle);
714 mat[2] = -((float) sin(angle));
715 mat[4] = 1.0f;
716 mat[6] = (float) sin(angle);
717 mat[8] = (float) cos(angle);
718 } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) {
719 //rotation around Z
720 mat[0] = (float) cos(angle);
721 mat[1] = (float) sin(angle);
722 mat[3] = -((float) sin(angle));
723 mat[4] = (float) cos(angle);
724 mat[8] = 1.0f;
725 } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) {
726 //arbitrary rotation
727 //normalize arbitrary axis
728 norm = (float) sqrt(vec->vec[0] * vec->vec[0] +
729 vec->vec[1] * vec->vec[1] +
730 vec->vec[2] * vec->vec[2]);
731 vec->vec[0] /= norm;
732 vec->vec[1] /= norm;
733 vec->vec[2] /= norm;
735 //create matrix
736 cosAngle = (float) cos(angle);
737 sinAngle = (float) sin(angle);
738 mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) +
739 cosAngle;
740 mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) +
741 (vec->vec[2] * sinAngle);
742 mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) -
743 (vec->vec[1] * sinAngle);
744 mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) -
745 (vec->vec[2] * sinAngle);
746 mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) +
747 cosAngle;
748 mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) +
749 (vec->vec[0] * sinAngle);
750 mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) +
751 (vec->vec[1] * sinAngle);
752 mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) -
753 (vec->vec[0] * sinAngle);
754 mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) +
755 cosAngle;
756 } else {
757 return EXPP_ReturnPyObjError(PyExc_AttributeError,
758 "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n");
760 if(matSize == 4) {
761 //resize matrix
762 mat[10] = mat[8];
763 mat[9] = mat[7];
764 mat[8] = mat[6];
765 mat[7] = 0.0f;
766 mat[6] = mat[5];
767 mat[5] = mat[4];
768 mat[4] = mat[3];
769 mat[3] = 0.0f;
771 //pass to matrix creation
772 return newMatrixObject(mat, matSize, matSize, Py_NEW);
774 //----------------------------------Mathutils.TranslationMatrix() -------
775 //creates a translation matrix
776 PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec)
778 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
779 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
781 if(!VectorObject_Check(vec)) {
782 return EXPP_ReturnPyObjError(PyExc_TypeError,
783 "Mathutils.TranslationMatrix(): expected vector\n");
785 if(vec->size != 3 && vec->size != 4) {
786 return EXPP_ReturnPyObjError(PyExc_TypeError,
787 "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n");
789 //create a identity matrix and add translation
790 Mat4One((float(*)[4]) mat);
791 mat[12] = vec->vec[0];
792 mat[13] = vec->vec[1];
793 mat[14] = vec->vec[2];
795 return newMatrixObject(mat, 4, 4, Py_NEW);
797 //----------------------------------Mathutils.ScaleMatrix() -------------
798 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
799 //creates a scaling matrix
800 PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
802 VectorObject *vec = NULL;
803 float norm = 0.0f, factor;
804 int matSize, x;
805 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
806 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
808 if(!PyArg_ParseTuple
809 (args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) {
810 return EXPP_ReturnPyObjError(PyExc_TypeError,
811 "Mathutils.ScaleMatrix(): expected float int and optional vector\n");
813 if(matSize != 2 && matSize != 3 && matSize != 4)
814 return EXPP_ReturnPyObjError(PyExc_AttributeError,
815 "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
816 if(vec) {
817 if(vec->size > 2 && matSize == 2)
818 return EXPP_ReturnPyObjError(PyExc_AttributeError,
819 "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n");
821 if(vec == NULL) { //scaling along axis
822 if(matSize == 2) {
823 mat[0] = factor;
824 mat[3] = factor;
825 } else {
826 mat[0] = factor;
827 mat[4] = factor;
828 mat[8] = factor;
830 } else { //scaling in arbitrary direction
831 //normalize arbitrary axis
832 for(x = 0; x < vec->size; x++) {
833 norm += vec->vec[x] * vec->vec[x];
835 norm = (float) sqrt(norm);
836 for(x = 0; x < vec->size; x++) {
837 vec->vec[x] /= norm;
839 if(matSize == 2) {
840 mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0]));
841 mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
842 mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
843 mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
844 } else {
845 mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0]));
846 mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
847 mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
848 mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
849 mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
850 mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
851 mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
852 mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
853 mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2]));
856 if(matSize == 4) {
857 //resize matrix
858 mat[10] = mat[8];
859 mat[9] = mat[7];
860 mat[8] = mat[6];
861 mat[7] = 0.0f;
862 mat[6] = mat[5];
863 mat[5] = mat[4];
864 mat[4] = mat[3];
865 mat[3] = 0.0f;
867 //pass to matrix creation
868 return newMatrixObject(mat, matSize, matSize, Py_NEW);
870 //----------------------------------Mathutils.OrthoProjectionMatrix() ---
871 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
872 //creates an ortho projection matrix
873 PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args)
875 VectorObject *vec = NULL;
876 char *plane;
877 int matSize, x;
878 float norm = 0.0f;
879 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
880 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
882 if(!PyArg_ParseTuple
883 (args, "si|O!", &plane, &matSize, &vector_Type, &vec)) {
884 return EXPP_ReturnPyObjError(PyExc_TypeError,
885 "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n");
887 if(matSize != 2 && matSize != 3 && matSize != 4)
888 return EXPP_ReturnPyObjError(PyExc_AttributeError,
889 "Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
890 if(vec) {
891 if(vec->size > 2 && matSize == 2)
892 return EXPP_ReturnPyObjError(PyExc_AttributeError,
893 "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n");
895 if(vec == NULL) { //ortho projection onto cardinal plane
896 if(((strcmp(plane, "x") == 0)
897 || (strcmp(plane, "X") == 0)) && matSize == 2) {
898 mat[0] = 1.0f;
899 } else if(((strcmp(plane, "y") == 0)
900 || (strcmp(plane, "Y") == 0))
901 && matSize == 2) {
902 mat[3] = 1.0f;
903 } else if(((strcmp(plane, "xy") == 0)
904 || (strcmp(plane, "XY") == 0))
905 && matSize > 2) {
906 mat[0] = 1.0f;
907 mat[4] = 1.0f;
908 } else if(((strcmp(plane, "xz") == 0)
909 || (strcmp(plane, "XZ") == 0))
910 && matSize > 2) {
911 mat[0] = 1.0f;
912 mat[8] = 1.0f;
913 } else if(((strcmp(plane, "yz") == 0)
914 || (strcmp(plane, "YZ") == 0))
915 && matSize > 2) {
916 mat[4] = 1.0f;
917 mat[8] = 1.0f;
918 } else {
919 return EXPP_ReturnPyObjError(PyExc_AttributeError,
920 "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n");
922 } else { //arbitrary plane
923 //normalize arbitrary axis
924 for(x = 0; x < vec->size; x++) {
925 norm += vec->vec[x] * vec->vec[x];
927 norm = (float) sqrt(norm);
928 for(x = 0; x < vec->size; x++) {
929 vec->vec[x] /= norm;
931 if(((strcmp(plane, "r") == 0)
932 || (strcmp(plane, "R") == 0)) && matSize == 2) {
933 mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
934 mat[1] = -(vec->vec[0] * vec->vec[1]);
935 mat[2] = -(vec->vec[0] * vec->vec[1]);
936 mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
937 } else if(((strcmp(plane, "r") == 0)
938 || (strcmp(plane, "R") == 0))
939 && matSize > 2) {
940 mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
941 mat[1] = -(vec->vec[0] * vec->vec[1]);
942 mat[2] = -(vec->vec[0] * vec->vec[2]);
943 mat[3] = -(vec->vec[0] * vec->vec[1]);
944 mat[4] = 1 - (vec->vec[1] * vec->vec[1]);
945 mat[5] = -(vec->vec[1] * vec->vec[2]);
946 mat[6] = -(vec->vec[0] * vec->vec[2]);
947 mat[7] = -(vec->vec[1] * vec->vec[2]);
948 mat[8] = 1 - (vec->vec[2] * vec->vec[2]);
949 } else {
950 return EXPP_ReturnPyObjError(PyExc_AttributeError,
951 "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n");
954 if(matSize == 4) {
955 //resize matrix
956 mat[10] = mat[8];
957 mat[9] = mat[7];
958 mat[8] = mat[6];
959 mat[7] = 0.0f;
960 mat[6] = mat[5];
961 mat[5] = mat[4];
962 mat[4] = mat[3];
963 mat[3] = 0.0f;
965 //pass to matrix creation
966 return newMatrixObject(mat, matSize, matSize, Py_NEW);
968 //----------------------------------Mathutils.ShearMatrix() -------------
969 //creates a shear matrix
970 PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
972 int matSize;
973 char *plane;
974 float factor;
975 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
976 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
978 if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) {
979 return EXPP_ReturnPyObjError(PyExc_TypeError,
980 "Mathutils.ShearMatrix(): expected string float and int\n");
982 if(matSize != 2 && matSize != 3 && matSize != 4)
983 return EXPP_ReturnPyObjError(PyExc_AttributeError,
984 "Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
986 if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0))
987 && matSize == 2) {
988 mat[0] = 1.0f;
989 mat[2] = factor;
990 mat[3] = 1.0f;
991 } else if(((strcmp(plane, "y") == 0)
992 || (strcmp(plane, "Y") == 0)) && matSize == 2) {
993 mat[0] = 1.0f;
994 mat[1] = factor;
995 mat[3] = 1.0f;
996 } else if(((strcmp(plane, "xy") == 0)
997 || (strcmp(plane, "XY") == 0)) && matSize > 2) {
998 mat[0] = 1.0f;
999 mat[4] = 1.0f;
1000 mat[6] = factor;
1001 mat[7] = factor;
1002 } else if(((strcmp(plane, "xz") == 0)
1003 || (strcmp(plane, "XZ") == 0)) && matSize > 2) {
1004 mat[0] = 1.0f;
1005 mat[3] = factor;
1006 mat[4] = 1.0f;
1007 mat[5] = factor;
1008 mat[8] = 1.0f;
1009 } else if(((strcmp(plane, "yz") == 0)
1010 || (strcmp(plane, "YZ") == 0)) && matSize > 2) {
1011 mat[0] = 1.0f;
1012 mat[1] = factor;
1013 mat[2] = factor;
1014 mat[4] = 1.0f;
1015 mat[8] = 1.0f;
1016 } else {
1017 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1018 "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n");
1020 if(matSize == 4) {
1021 //resize matrix
1022 mat[10] = mat[8];
1023 mat[9] = mat[7];
1024 mat[8] = mat[6];
1025 mat[7] = 0.0f;
1026 mat[6] = mat[5];
1027 mat[5] = mat[4];
1028 mat[4] = mat[3];
1029 mat[3] = 0.0f;
1031 //pass to matrix creation
1032 return newMatrixObject(mat, matSize, matSize, Py_NEW);
1034 //----------------------------------QUATERNION FUNCTIONS-----------------
1035 //----------------------------------Mathutils.Quaternion() --------------
1036 PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args)
1038 PyObject *listObject = NULL, *n, *q, *f;
1039 int size, i;
1040 float quat[4];
1041 double norm = 0.0f, angle = 0.0f;
1043 size = PySequence_Length(args);
1044 if (size == 1 || size == 2) { //seq?
1045 listObject = PySequence_GetItem(args, 0);
1046 if (PySequence_Check(listObject)) {
1047 size = PySequence_Length(listObject);
1048 if ((size == 4 && PySequence_Length(args) !=1) ||
1049 (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) {
1050 // invalid args/size
1051 Py_DECREF(listObject);
1052 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1053 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1055 if(size == 3){ //get angle in axis/angle
1056 n = PyNumber_Float(PySequence_GetItem(args, 1));
1057 if(n == NULL) { // parsed item not a number or getItem fail
1058 Py_DECREF(listObject);
1059 return EXPP_ReturnPyObjError(PyExc_TypeError,
1060 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1062 angle = PyFloat_AS_DOUBLE(n);
1063 Py_DECREF(n);
1065 }else{
1066 listObject = PySequence_GetItem(args, 1);
1067 if (size>1 && PySequence_Check(listObject)) {
1068 size = PySequence_Length(listObject);
1069 if (size != 3) {
1070 // invalid args/size
1071 Py_DECREF(listObject);
1072 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1073 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1075 n = PyNumber_Float(PySequence_GetItem(args, 0));
1076 if(n == NULL) { // parsed item not a number or getItem fail
1077 Py_DECREF(listObject);
1078 return EXPP_ReturnPyObjError(PyExc_TypeError,
1079 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1081 angle = PyFloat_AS_DOUBLE(n);
1082 Py_DECREF(n);
1083 } else { // argument was not a sequence
1084 Py_XDECREF(listObject);
1085 return EXPP_ReturnPyObjError(PyExc_TypeError,
1086 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1089 } else if (size == 0) { //returns a new empty quat
1090 return newQuaternionObject(NULL, Py_NEW);
1091 } else {
1092 listObject = EXPP_incr_ret(args);
1095 if (size == 3) { // invalid quat size
1096 if(PySequence_Length(args) != 2){
1097 Py_DECREF(listObject);
1098 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1099 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1101 }else{
1102 if(size != 4){
1103 Py_DECREF(listObject);
1104 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1105 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1109 for (i=0; i<size; i++) { //parse
1110 q = PySequence_GetItem(listObject, i);
1111 if (q == NULL) { // Failed to read sequence
1112 Py_DECREF(listObject);
1113 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
1114 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1117 f = PyNumber_Float(q);
1118 if(f == NULL) { // parsed item not a number
1119 EXPP_decr2(q, listObject);
1120 return EXPP_ReturnPyObjError(PyExc_TypeError,
1121 "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
1124 quat[i] = (float)PyFloat_AS_DOUBLE(f);
1125 EXPP_decr2(f, q);
1127 if(size == 3){ //calculate the quat based on axis/angle
1128 norm = sqrt(quat[0] * quat[0] + quat[1] * quat[1] + quat[2] * quat[2]);
1129 quat[0] /= (float)norm;
1130 quat[1] /= (float)norm;
1131 quat[2] /= (float)norm;
1133 angle = angle * (Py_PI / 180);
1134 quat[3] =(float) (sin(angle/ 2.0f)) * quat[2];
1135 quat[2] =(float) (sin(angle/ 2.0f)) * quat[1];
1136 quat[1] =(float) (sin(angle/ 2.0f)) * quat[0];
1137 quat[0] =(float) (cos(angle/ 2.0f));
1140 Py_DECREF(listObject);
1141 return newQuaternionObject(quat, Py_NEW);
1143 //----------------------------------Mathutils.CrossQuats() ----------------
1144 //quaternion multiplication - associate not commutative
1145 PyObject *M_Mathutils_CrossQuats(PyObject * self, PyObject * args)
1147 QuaternionObject *quatU = NULL, *quatV = NULL;
1148 float quat[4];
1150 if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU,
1151 &quaternion_Type, &quatV))
1152 return EXPP_ReturnPyObjError(PyExc_TypeError,"Mathutils.CrossQuats(): expected Quaternion types");
1153 QuatMul(quat, quatU->quat, quatV->quat);
1155 return newQuaternionObject(quat, Py_NEW);
1157 //----------------------------------Mathutils.DotQuats() ----------------
1158 //returns the dot product of 2 quaternions
1159 PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args)
1161 QuaternionObject *quatU = NULL, *quatV = NULL;
1162 double dot = 0.0f;
1163 int x;
1165 if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU,
1166 &quaternion_Type, &quatV))
1167 return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DotQuats(): expected Quaternion types");
1169 for(x = 0; x < 4; x++) {
1170 dot += quatU->quat[x] * quatV->quat[x];
1172 return PyFloat_FromDouble(dot);
1174 //----------------------------------Mathutils.DifferenceQuats() ---------
1175 //returns the difference between 2 quaternions
1176 PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args)
1178 QuaternionObject *quatU = NULL, *quatV = NULL;
1179 float quat[4], tempQuat[4];
1180 double dot = 0.0f;
1181 int x;
1183 if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type,
1184 &quatU, &quaternion_Type, &quatV))
1185 return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types");
1187 tempQuat[0] = quatU->quat[0];
1188 tempQuat[1] = -quatU->quat[1];
1189 tempQuat[2] = -quatU->quat[2];
1190 tempQuat[3] = -quatU->quat[3];
1192 dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] +
1193 tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]);
1195 for(x = 0; x < 4; x++) {
1196 tempQuat[x] /= (float)(dot * dot);
1198 QuatMul(quat, tempQuat, quatV->quat);
1199 return newQuaternionObject(quat, Py_NEW);
1201 //----------------------------------Mathutils.Slerp() ------------------
1202 //attemps to interpolate 2 quaternions and return the result
1203 PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args)
1205 QuaternionObject *quatU = NULL, *quatV = NULL;
1206 float quat[4], quat_u[4], quat_v[4], param;
1207 double x, y, dot, sinT, angle, IsinT;
1208 int z;
1210 if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type,
1211 &quatU, &quaternion_Type, &quatV, &param))
1212 return EXPP_ReturnPyObjError(PyExc_TypeError,
1213 "Mathutils.Slerp(): expected Quaternion types and float");
1215 if(param > 1.0f || param < 0.0f)
1216 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1217 "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
1219 //copy quats
1220 for(z = 0; z < 4; z++){
1221 quat_u[z] = quatU->quat[z];
1222 quat_v[z] = quatV->quat[z];
1225 //dot product
1226 dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] +
1227 quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3];
1229 //if negative negate a quat (shortest arc)
1230 if(dot < 0.0f) {
1231 quat_v[0] = -quat_v[0];
1232 quat_v[1] = -quat_v[1];
1233 quat_v[2] = -quat_v[2];
1234 quat_v[3] = -quat_v[3];
1235 dot = -dot;
1237 if(dot > .99999f) { //very close
1238 x = 1.0f - param;
1239 y = param;
1240 } else {
1241 //calculate sin of angle
1242 sinT = sqrt(1.0f - (dot * dot));
1243 //calculate angle
1244 angle = atan2(sinT, dot);
1245 //caluculate inverse of sin(theta)
1246 IsinT = 1.0f / sinT;
1247 x = sin((1.0f - param) * angle) * IsinT;
1248 y = sin(param * angle) * IsinT;
1250 //interpolate
1251 quat[0] = (float)(quat_u[0] * x + quat_v[0] * y);
1252 quat[1] = (float)(quat_u[1] * x + quat_v[1] * y);
1253 quat[2] = (float)(quat_u[2] * x + quat_v[2] * y);
1254 quat[3] = (float)(quat_u[3] * x + quat_v[3] * y);
1256 return newQuaternionObject(quat, Py_NEW);
1258 //----------------------------------EULER FUNCTIONS----------------------
1259 //----------------------------------Mathutils.Euler() -------------------
1260 //makes a new euler for you to play with
1261 PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args)
1264 PyObject *listObject = NULL;
1265 int size, i;
1266 float eul[3];
1267 PyObject *e, *f;
1269 size = PySequence_Length(args);
1270 if (size == 1) {
1271 listObject = PySequence_GetItem(args, 0);
1272 if (PySequence_Check(listObject)) {
1273 size = PySequence_Length(listObject);
1274 } else { // Single argument was not a sequence
1275 Py_DECREF(listObject);
1276 return EXPP_ReturnPyObjError(PyExc_TypeError,
1277 "Mathutils.Euler(): 3d numeric sequence expected\n");
1279 } else if (size == 0) {
1280 //returns a new empty 3d euler
1281 return newEulerObject(NULL, Py_NEW);
1282 } else {
1283 listObject = EXPP_incr_ret(args);
1286 if (size != 3) { // Invalid euler size
1287 Py_DECREF(listObject);
1288 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1289 "Mathutils.Euler(): 3d numeric sequence expected\n");
1292 for (i=0; i<size; i++) {
1293 e = PySequence_GetItem(listObject, i);
1294 if (e == NULL) { // Failed to read sequence
1295 Py_DECREF(listObject);
1296 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
1297 "Mathutils.Euler(): 3d numeric sequence expected\n");
1300 f = PyNumber_Float(e);
1301 if(f == NULL) { // parsed item not a number
1302 EXPP_decr2(e, listObject);
1303 return EXPP_ReturnPyObjError(PyExc_TypeError,
1304 "Mathutils.Euler(): 3d numeric sequence expected\n");
1307 eul[i]=(float)PyFloat_AS_DOUBLE(f);
1308 EXPP_decr2(f,e);
1310 Py_DECREF(listObject);
1311 return newEulerObject(eul, Py_NEW);
1313 //----------------------------------POINT FUNCTIONS---------------------
1314 //----------------------------------Mathutils.Point() ------------------
1315 PyObject *M_Mathutils_Point(PyObject * self, PyObject * args)
1317 PyObject *listObject = NULL;
1318 int size, i;
1319 float point[3];
1320 PyObject *v, *f;
1322 size = PySequence_Length(args);
1323 if (size == 1) {
1324 listObject = PySequence_GetItem(args, 0);
1325 if (PySequence_Check(listObject)) {
1326 size = PySequence_Length(listObject);
1327 } else { // Single argument was not a sequence
1328 Py_XDECREF(listObject);
1329 return EXPP_ReturnPyObjError(PyExc_TypeError,
1330 "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
1332 } else if (size == 0) {
1333 //returns a new empty 3d point
1334 return newPointObject(NULL, 3, Py_NEW);
1335 } else {
1336 listObject = EXPP_incr_ret(args);
1339 if (size<2 || size>3) { // Invalid vector size
1340 Py_XDECREF(listObject);
1341 return EXPP_ReturnPyObjError(PyExc_AttributeError,
1342 "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
1345 for (i=0; i<size; i++) {
1346 v=PySequence_GetItem(listObject, i);
1347 if (v==NULL) { // Failed to read sequence
1348 Py_XDECREF(listObject);
1349 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
1350 "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
1353 f=PyNumber_Float(v);
1354 if(f==NULL) { // parsed item not a number
1355 Py_DECREF(v);
1356 Py_XDECREF(listObject);
1357 return EXPP_ReturnPyObjError(PyExc_TypeError,
1358 "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
1361 point[i]=(float)PyFloat_AS_DOUBLE(f);
1362 EXPP_decr2(f,v);
1364 Py_DECREF(listObject);
1365 return newPointObject(point, size, Py_NEW);
1367 //---------------------------------INTERSECTION FUNCTIONS--------------------
1368 //----------------------------------Mathutils.Intersect() -------------------
1369 PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
1371 VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
1372 float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
1373 float det, inv_det, u, v, t;
1374 int clip = 1;
1376 if( !PyArg_ParseTuple
1377 ( args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2
1378 , &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip) )
1379 return ( EXPP_ReturnPyObjError
1380 ( PyExc_TypeError, "expected 5 vector types\n" ) );
1381 if( vec1->size != 3 || vec2->size != 3 || vec3->size != 3 ||
1382 ray->size != 3 || ray_off->size != 3)
1383 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1384 "only 3D vectors for all parameters\n" ) );
1386 VECCOPY(v1, vec1->vec);
1387 VECCOPY(v2, vec2->vec);
1388 VECCOPY(v3, vec3->vec);
1390 VECCOPY(dir, ray->vec);
1391 Normalize(dir);
1393 VECCOPY(orig, ray_off->vec);
1395 /* find vectors for two edges sharing v1 */
1396 VecSubf(e1, v2, v1);
1397 VecSubf(e2, v3, v1);
1399 /* begin calculating determinant - also used to calculated U parameter */
1400 Crossf(pvec, dir, e2);
1402 /* if determinant is near zero, ray lies in plane of triangle */
1403 det = Inpf(e1, pvec);
1405 if (det > -0.000001 && det < 0.000001) {
1406 return EXPP_incr_ret( Py_None );
1409 inv_det = 1.0f / det;
1411 /* calculate distance from v1 to ray origin */
1412 VecSubf(tvec, orig, v1);
1414 /* calculate U parameter and test bounds */
1415 u = Inpf(tvec, pvec) * inv_det;
1416 if (clip && (u < 0.0f || u > 1.0f)) {
1417 return EXPP_incr_ret( Py_None );
1420 /* prepare to test the V parameter */
1421 Crossf(qvec, tvec, e1);
1423 /* calculate V parameter and test bounds */
1424 v = Inpf(dir, qvec) * inv_det;
1426 if (clip && (v < 0.0f || u + v > 1.0f)) {
1427 return EXPP_incr_ret( Py_None );
1430 /* calculate t, ray intersects triangle */
1431 t = Inpf(e2, qvec) * inv_det;
1433 VecMulf(dir, t);
1434 VecAddf(pvec, orig, dir);
1436 return newVectorObject(pvec, 3, Py_NEW);
1438 //----------------------------------Mathutils.LineIntersect() -------------------
1439 /* Line-Line intersection using algorithm from mathworld.wolfram.com */
1440 PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args )
1442 PyObject * tuple;
1443 VectorObject *vec1, *vec2, *vec3, *vec4;
1444 float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
1446 if( !PyArg_ParseTuple
1447 ( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
1448 , &vector_Type, &vec3, &vector_Type, &vec4 ) )
1449 return ( EXPP_ReturnPyObjError
1450 ( PyExc_TypeError, "expected 4 vector types\n" ) );
1451 if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size)
1452 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1453 "vectors must be of the same size\n" ) );
1455 if( vec1->size == 3 || vec1->size == 2) {
1456 float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3];
1457 float d;
1458 if (vec1->size == 3) {
1459 VECCOPY(v1, vec1->vec);
1460 VECCOPY(v2, vec2->vec);
1461 VECCOPY(v3, vec3->vec);
1462 VECCOPY(v4, vec4->vec);
1464 else {
1465 v1[0] = vec1->vec[0];
1466 v1[1] = vec1->vec[1];
1467 v1[2] = 0.0f;
1469 v2[0] = vec2->vec[0];
1470 v2[1] = vec2->vec[1];
1471 v2[2] = 0.0f;
1473 v3[0] = vec3->vec[0];
1474 v3[1] = vec3->vec[1];
1475 v3[2] = 0.0f;
1477 v4[0] = vec4->vec[0];
1478 v4[1] = vec4->vec[1];
1479 v4[2] = 0.0f;
1482 VecSubf(c, v3, v1);
1483 VecSubf(a, v2, v1);
1484 VecSubf(b, v4, v3);
1486 VECCOPY(dir1, a);
1487 Normalize(dir1);
1488 VECCOPY(dir2, b);
1489 Normalize(dir2);
1490 d = Inpf(dir1, dir2);
1491 if (d == 1.0f || d == -1.0f) {
1492 /* colinear */
1493 return EXPP_incr_ret( Py_None );
1496 Crossf(ab, a, b);
1497 d = Inpf(c, ab);
1499 /* test if the two lines are coplanar */
1500 if (d > -0.000001f && d < 0.000001f) {
1501 Crossf(cb, c, b);
1503 VecMulf(a, Inpf(cb, ab) / Inpf(ab, ab));
1504 VecAddf(i1, v1, a);
1505 VECCOPY(i2, i1);
1507 /* if not */
1508 else {
1509 float n[3], t[3];
1510 VecSubf(t, v1, v3);
1512 /* offset between both plane where the lines lies */
1513 Crossf(n, a, b);
1514 Projf(t, t, n);
1516 /* for the first line, offset the second line until it is coplanar */
1517 VecAddf(v3, v3, t);
1518 VecAddf(v4, v4, t);
1520 VecSubf(c, v3, v1);
1521 VecSubf(a, v2, v1);
1522 VecSubf(b, v4, v3);
1524 Crossf(ab, a, b);
1525 Crossf(cb, c, b);
1527 VecMulf(a, Inpf(cb, ab) / Inpf(ab, ab));
1528 VecAddf(i1, v1, a);
1530 /* for the second line, just substract the offset from the first intersection point */
1531 VecSubf(i2, i1, t);
1534 tuple = PyTuple_New( 2 );
1535 PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW) );
1536 PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW) );
1537 return tuple;
1539 else {
1540 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1541 "2D/3D vectors only\n" ) );
1547 //---------------------------------NORMALS FUNCTIONS--------------------
1548 //----------------------------------Mathutils.QuadNormal() -------------------
1549 PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
1551 VectorObject *vec1;
1552 VectorObject *vec2;
1553 VectorObject *vec3;
1554 VectorObject *vec4;
1555 float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3];
1557 if( !PyArg_ParseTuple
1558 ( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
1559 , &vector_Type, &vec3, &vector_Type, &vec4 ) )
1560 return ( EXPP_ReturnPyObjError
1561 ( PyExc_TypeError, "expected 4 vector types\n" ) );
1562 if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size)
1563 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1564 "vectors must be of the same size\n" ) );
1565 if( vec1->size != 3 )
1566 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1567 "only 3D vectors\n" ) );
1569 VECCOPY(v1, vec1->vec);
1570 VECCOPY(v2, vec2->vec);
1571 VECCOPY(v3, vec3->vec);
1572 VECCOPY(v4, vec4->vec);
1574 /* find vectors for two edges sharing v2 */
1575 VecSubf(e1, v1, v2);
1576 VecSubf(e2, v3, v2);
1578 Crossf(n1, e2, e1);
1579 Normalize(n1);
1581 /* find vectors for two edges sharing v4 */
1582 VecSubf(e1, v3, v4);
1583 VecSubf(e2, v1, v4);
1585 Crossf(n2, e2, e1);
1586 Normalize(n2);
1588 /* adding and averaging the normals of both triangles */
1589 VecAddf(n1, n2, n1);
1590 Normalize(n1);
1592 return newVectorObject(n1, 3, Py_NEW);
1595 //----------------------------Mathutils.TriangleNormal() -------------------
1596 PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args )
1598 VectorObject *vec1, *vec2, *vec3;
1599 float v1[3], v2[3], v3[3], e1[3], e2[3], n[3];
1601 if( !PyArg_ParseTuple
1602 ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
1603 , &vector_Type, &vec3 ) )
1604 return ( EXPP_ReturnPyObjError
1605 ( PyExc_TypeError, "expected 3 vector types\n" ) );
1606 if( vec1->size != vec2->size || vec1->size != vec3->size )
1607 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1608 "vectors must be of the same size\n" ) );
1609 if( vec1->size != 3 )
1610 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1611 "only 3D vectors\n" ) );
1613 VECCOPY(v1, vec1->vec);
1614 VECCOPY(v2, vec2->vec);
1615 VECCOPY(v3, vec3->vec);
1617 /* find vectors for two edges sharing v2 */
1618 VecSubf(e1, v1, v2);
1619 VecSubf(e2, v3, v2);
1621 Crossf(n, e2, e1);
1622 Normalize(n);
1624 return newVectorObject(n, 3, Py_NEW);
1627 //--------------------------------- AREA FUNCTIONS--------------------
1628 //----------------------------------Mathutils.TriangleArea() -------------------
1629 PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args )
1631 VectorObject *vec1, *vec2, *vec3;
1632 float v1[3], v2[3], v3[3];
1634 if( !PyArg_ParseTuple
1635 ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
1636 , &vector_Type, &vec3 ) )
1637 return ( EXPP_ReturnPyObjError
1638 ( PyExc_TypeError, "expected 3 vector types\n" ) );
1639 if( vec1->size != vec2->size || vec1->size != vec3->size )
1640 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1641 "vectors must be of the same size\n" ) );
1643 if (vec1->size == 3) {
1644 VECCOPY(v1, vec1->vec);
1645 VECCOPY(v2, vec2->vec);
1646 VECCOPY(v3, vec3->vec);
1648 return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3) );
1650 else if (vec1->size == 2) {
1651 v1[0] = vec1->vec[0];
1652 v1[1] = vec1->vec[1];
1654 v2[0] = vec2->vec[0];
1655 v2[1] = vec2->vec[1];
1657 v3[0] = vec3->vec[0];
1658 v3[1] = vec3->vec[1];
1660 return PyFloat_FromDouble( AreaF2Dfl(v1, v2, v3) );
1662 else {
1663 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
1664 "only 2D,3D vectors are supported\n" ) );
1667 //#############################DEPRECATED################################
1668 //#######################################################################
1669 //----------------------------------Mathutils.CopyMat() -----------------
1670 //copies a matrix into a new matrix
1671 PyObject *M_Mathutils_CopyMat(PyObject * self, PyObject * args)
1673 PyObject *matrix = NULL;
1674 static char warning = 1;
1676 if( warning ) {
1677 printf("Mathutils.CopyMat(): deprecated :use Mathutils.Matrix() to copy matrices\n");
1678 --warning;
1681 matrix = M_Mathutils_Matrix(self, args);
1682 if(matrix == NULL)
1683 return NULL; //error string already set if we get here
1684 else
1685 return matrix;
1687 //----------------------------------Mathutils.CopyVec() -----------------
1688 //makes a new vector that is a copy of the input
1689 PyObject *M_Mathutils_CopyVec(PyObject * self, PyObject * args)
1691 PyObject *vec = NULL;
1692 static char warning = 1;
1694 if( warning ) {
1695 printf("Mathutils.CopyVec(): Deprecated: use Mathutils.Vector() to copy vectors\n");
1696 --warning;
1699 vec = M_Mathutils_Vector(self, args);
1700 if(vec == NULL)
1701 return NULL; //error string already set if we get here
1702 else
1703 return vec;
1705 //----------------------------------Mathutils.CopyQuat() --------------
1706 //Copies a quaternion to a new quat
1707 PyObject *M_Mathutils_CopyQuat(PyObject * self, PyObject * args)
1709 PyObject *quat = NULL;
1710 static char warning = 1;
1712 if( warning ) {
1713 printf("Mathutils.CopyQuat(): Deprecated: use Mathutils.Quaternion() to copy vectors\n");
1714 --warning;
1717 quat = M_Mathutils_Quaternion(self, args);
1718 if(quat == NULL)
1719 return NULL; //error string already set if we get here
1720 else
1721 return quat;
1723 //----------------------------------Mathutils.CopyEuler() ---------------
1724 //copies a euler to a new euler
1725 PyObject *M_Mathutils_CopyEuler(PyObject * self, PyObject * args)
1727 PyObject *eul = NULL;
1728 static char warning = 1;
1730 if( warning ) {
1731 printf("Mathutils.CopyEuler(): deprecated:use Mathutils.Euler() to copy vectors\n");
1732 --warning;
1735 eul = M_Mathutils_Euler(self, args);
1736 if(eul == NULL)
1737 return NULL; //error string already set if we get here
1738 else
1739 return eul;
1741 //----------------------------------Mathutils.RotateEuler() ------------
1742 //rotates a euler a certain amount and returns the result
1743 //should return a unique euler rotation (i.e. no 720 degree pitches :)
1744 PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args)
1746 EulerObject *Eul = NULL;
1747 float angle;
1748 char *axis;
1749 static char warning = 1;
1751 if( warning ) {
1752 printf("Mathutils.RotateEuler(): Deprecated:use Euler.rotate() to rotate a euler\n");
1753 --warning;
1756 if(!PyArg_ParseTuple(args, "O!fs", &euler_Type, &Eul, &angle, &axis))
1757 return EXPP_ReturnPyObjError(PyExc_TypeError,
1758 "Mathutils.RotateEuler(): expected euler type & float & string");
1760 Euler_Rotate(Eul, Py_BuildValue("fs", angle, axis));
1761 Py_RETURN_NONE;
1763 //----------------------------------Mathutils.MatMultVec() --------------
1764 //COLUMN VECTOR Multiplication (Matrix X Vector)
1765 PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args)
1767 MatrixObject *mat = NULL;
1768 VectorObject *vec = NULL;
1769 static char warning = 1;
1771 if( warning ) {
1772 printf("Mathutils.MatMultVec(): Deprecated: use matrix * vec to perform column vector multiplication\n");
1773 --warning;
1776 //get pyObjects
1777 if(!PyArg_ParseTuple(args, "O!O!", &matrix_Type, &mat, &vector_Type, &vec))
1778 return EXPP_ReturnPyObjError(PyExc_TypeError,
1779 "Mathutils.MatMultVec(): MatMultVec() expects a matrix and a vector object - in that order\n");
1781 return column_vector_multiplication(mat, vec);
1783 //----------------------------------Mathutils.VecMultMat() ---------------
1784 //ROW VECTOR Multiplication - Vector X Matrix
1785 PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args)
1787 MatrixObject *mat = NULL;
1788 VectorObject *vec = NULL;
1789 static char warning = 1;
1791 if( warning ) {
1792 printf("Mathutils.VecMultMat(): Deprecated: use vec * matrix to perform row vector multiplication\n");
1793 --warning;
1796 //get pyObjects
1797 if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec, &matrix_Type, &mat))
1798 return EXPP_ReturnPyObjError(PyExc_TypeError,
1799 "Mathutils.VecMultMat(): VecMultMat() expects a vector and matrix object - in that order\n");
1801 return row_vector_multiplication(vec, mat);
1803 //#######################################################################
1804 //#############################DEPRECATED################################