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