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
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"
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)
117 //seed the generator for the rand function
118 BLI_srand((unsigned int) (PIL_check_seconds_timer() *
121 /* needed for getseters */
122 if( PyType_Ready( &vector_Type
) < 0 )
124 if( PyType_Ready( &matrix_Type
) < 0 )
126 if( PyType_Ready( &euler_Type
) < 0 )
128 if( PyType_Ready( &quaternion_Type
) < 0 )
131 submodule
= Py_InitModule3("Blender.Mathutils",
132 M_Mathutils_methods
, M_Mathutils_doc
);
135 //-----------------------------METHODS----------------------------
136 //----------------column_vector_multiplication (internal)---------
137 //COLUMN VECTOR Multiplication (Matrix X Vector)
141 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
142 PyObject
*column_vector_multiplication(MatrixObject
* mat
, VectorObject
* vec
)
144 float vecNew
[4], vecCopy
[4];
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");
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
;
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];
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");
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
;
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]
205 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
206 PyObject
*row_vector_multiplication(VectorObject
* vec
, MatrixObject
* mat
)
208 float vecNew
[4], vecCopy
[4];
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");
221 for(x
= 0; x
< vec_size
; x
++){
222 vecCopy
[x
] = vec
->vec
[x
];
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
;
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];
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");
251 for(x
= 0; x
< pt
->size
; x
++){
252 ptCopy
[x
] = pt
->coord
[x
];
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
;
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
)
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
;
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
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
;
390 size
= PySequence_Length(args
);
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
);
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");
422 if(f
==NULL
) { // parsed item not a number
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
);
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
);
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
;
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
;
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....
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
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
));
511 return EXPP_ReturnPyObjError(PyExc_AttributeError
,
512 "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
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
;
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
;
544 double dot
= 0.0f
, dot2
= 0.0f
;
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...
558 for(x
= 0; x
< size
; x
++) {
559 dot
+= vec1
->vec
[x
] * vec2
->vec
[x
];
560 dot2
+= vec2
->vec
[x
] * vec2
->vec
[x
];
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
;
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
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
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
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
);
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
;
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
};
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
)
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");
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");
693 return EXPP_ReturnPyObjError(PyExc_AttributeError
,
694 "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
697 angle
= angle
* (float) (Py_PI
/ 180);
698 if(axis
== NULL
&& matSize
== 2) {
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)) {
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)) {
713 mat
[0] = (float) cos(angle
);
714 mat
[2] = -((float) sin(angle
));
716 mat
[6] = (float) sin(angle
);
717 mat
[8] = (float) cos(angle
);
718 } else if((strcmp(axis
, "z") == 0) || (strcmp(axis
, "Z") == 0)) {
720 mat
[0] = (float) cos(angle
);
721 mat
[1] = (float) sin(angle
);
722 mat
[3] = -((float) sin(angle
));
723 mat
[4] = (float) cos(angle
);
725 } else if((strcmp(axis
, "r") == 0) || (strcmp(axis
, "R") == 0)) {
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]);
736 cosAngle
= (float) cos(angle
);
737 sinAngle
= (float) sin(angle
);
738 mat
[0] = ((vec
->vec
[0] * vec
->vec
[0]) * (1 - 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
)) +
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
)) +
757 return EXPP_ReturnPyObjError(PyExc_AttributeError
,
758 "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n");
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
;
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
};
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");
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
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
++) {
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]));
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]));
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
;
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
};
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");
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) {
899 } else if(((strcmp(plane
, "y") == 0)
900 || (strcmp(plane
, "Y") == 0))
903 } else if(((strcmp(plane
, "xy") == 0)
904 || (strcmp(plane
, "XY") == 0))
908 } else if(((strcmp(plane
, "xz") == 0)
909 || (strcmp(plane
, "XZ") == 0))
913 } else if(((strcmp(plane
, "yz") == 0)
914 || (strcmp(plane
, "YZ") == 0))
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
++) {
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))
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]);
950 return EXPP_ReturnPyObjError(PyExc_AttributeError
,
951 "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n");
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
)
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))
991 } else if(((strcmp(plane
, "y") == 0)
992 || (strcmp(plane
, "Y") == 0)) && matSize
== 2) {
996 } else if(((strcmp(plane
, "xy") == 0)
997 || (strcmp(plane
, "XY") == 0)) && matSize
> 2) {
1002 } else if(((strcmp(plane
, "xz") == 0)
1003 || (strcmp(plane
, "XZ") == 0)) && matSize
> 2) {
1009 } else if(((strcmp(plane
, "yz") == 0)
1010 || (strcmp(plane
, "YZ") == 0)) && matSize
> 2) {
1017 return EXPP_ReturnPyObjError(PyExc_AttributeError
,
1018 "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n");
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
;
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
);
1066 listObject
= PySequence_GetItem(args
, 1);
1067 if (size
>1 && PySequence_Check(listObject
)) {
1068 size
= PySequence_Length(listObject
);
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
);
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
);
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");
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
);
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
;
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
;
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];
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
;
1210 if(!PyArg_ParseTuple(args
, "O!O!f", &quaternion_Type
,
1211 &quatU
, &quaternion_Type
, &quatV
, ¶m
))
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");
1220 for(z
= 0; z
< 4; z
++){
1221 quat_u
[z
] = quatU
->quat
[z
];
1222 quat_v
[z
] = quatV
->quat
[z
];
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)
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];
1237 if(dot
> .99999f
) { //very close
1241 //calculate sin of angle
1242 sinT
= sqrt(1.0f
- (dot
* dot
));
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
;
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
;
1269 size
= PySequence_Length(args
);
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
);
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
);
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
;
1322 size
= PySequence_Length(args
);
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
);
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
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
);
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
;
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
);
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
;
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
)
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];
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
);
1465 v1
[0] = vec1
->vec
[0];
1466 v1
[1] = vec1
->vec
[1];
1469 v2
[0] = vec2
->vec
[0];
1470 v2
[1] = vec2
->vec
[1];
1473 v3
[0] = vec3
->vec
[0];
1474 v3
[1] = vec3
->vec
[1];
1477 v4
[0] = vec4
->vec
[0];
1478 v4
[1] = vec4
->vec
[1];
1490 d
= Inpf(dir1
, dir2
);
1491 if (d
== 1.0f
|| d
== -1.0f
) {
1493 return EXPP_incr_ret( Py_None
);
1499 /* test if the two lines are coplanar */
1500 if (d
> -0.000001f
&& d
< 0.000001f
) {
1503 VecMulf(a
, Inpf(cb
, ab
) / Inpf(ab
, ab
));
1512 /* offset between both plane where the lines lies */
1516 /* for the first line, offset the second line until it is coplanar */
1527 VecMulf(a
, Inpf(cb
, ab
) / Inpf(ab
, ab
));
1530 /* for the second line, just substract the offset from the first intersection point */
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
) );
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
)
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
);
1581 /* find vectors for two edges sharing v4 */
1582 VecSubf(e1
, v3
, v4
);
1583 VecSubf(e2
, v1
, v4
);
1588 /* adding and averaging the normals of both triangles */
1589 VecAddf(n1
, n2
, 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
);
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
) );
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;
1677 printf("Mathutils.CopyMat(): deprecated :use Mathutils.Matrix() to copy matrices\n");
1681 matrix
= M_Mathutils_Matrix(self
, args
);
1683 return NULL
; //error string already set if we get here
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;
1695 printf("Mathutils.CopyVec(): Deprecated: use Mathutils.Vector() to copy vectors\n");
1699 vec
= M_Mathutils_Vector(self
, args
);
1701 return NULL
; //error string already set if we get here
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;
1713 printf("Mathutils.CopyQuat(): Deprecated: use Mathutils.Quaternion() to copy vectors\n");
1717 quat
= M_Mathutils_Quaternion(self
, args
);
1719 return NULL
; //error string already set if we get here
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;
1731 printf("Mathutils.CopyEuler(): deprecated:use Mathutils.Euler() to copy vectors\n");
1735 eul
= M_Mathutils_Euler(self
, args
);
1737 return NULL
; //error string already set if we get here
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
;
1749 static char warning
= 1;
1752 printf("Mathutils.RotateEuler(): Deprecated:use Euler.rotate() to rotate a euler\n");
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
));
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;
1772 printf("Mathutils.MatMultVec(): Deprecated: use matrix * vec to perform column vector multiplication\n");
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;
1792 printf("Mathutils.VecMultMat(): Deprecated: use vec * matrix to perform row vector multiplication\n");
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################################