svn merge ^/trunk/blender -r40720:40872
[blender.git] / source / blender / python / mathutils / mathutils.c
1 /* 
2  * $Id: mathutils.c 38409 2011-07-15 04:01:47Z campbellbarton $
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/python/generic/mathutils.c
31  *  \ingroup pygen
32  */
33
34 #include <Python.h>
35
36 #include "mathutils.h"
37
38 #include "BLI_math.h"
39 #include "BLI_utildefines.h"
40
41 PyDoc_STRVAR(M_Mathutils_doc,
42 "This module provides access to matrices, eulers, quaternions and vectors."
43 );
44 static int mathutils_array_parse_fast(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
45 {
46         PyObject *value_fast= NULL;
47         PyObject *item;
48
49         int i, size;
50
51         /* non list/tuple cases */
52         if(!(value_fast=PySequence_Fast(value, error_prefix))) {
53                 /* PySequence_Fast sets the error */
54                 return -1;
55         }
56
57         size= PySequence_Fast_GET_SIZE(value_fast);
58
59         if(size > array_max || size < array_min) {
60                 if (array_max == array_min)     {
61                         PyErr_Format(PyExc_ValueError,
62                                      "%.200s: sequence size is %d, expected %d",
63                                      error_prefix, size, array_max);
64                 }
65                 else {
66                         PyErr_Format(PyExc_ValueError,
67                                      "%.200s: sequence size is %d, expected [%d - %d]",
68                                      error_prefix, size, array_min, array_max);
69                 }
70                 Py_DECREF(value_fast);
71                 return -1;
72         }
73
74         i= size;
75         do {
76                 i--;
77                 if(((array[i]= PyFloat_AsDouble((item= PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0f) && PyErr_Occurred()) {
78                         PyErr_Format(PyExc_TypeError,
79                                      "%.200s: sequence index %d expected a number, "
80                                      "found '%.200s' type, ",
81                                      error_prefix, i, Py_TYPE(item)->tp_name);
82                         Py_DECREF(value_fast);
83                         return -1;
84                 }
85         } while(i);
86
87         Py_XDECREF(value_fast);
88         return size;
89 }
90
91 /* helper functionm returns length of the 'value', -1 on error */
92 int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
93 {
94 #if 1 /* approx 6x speedup for mathutils types */
95         int size;
96
97         if(     (size= VectorObject_Check(value)     ? ((VectorObject *)value)->size : 0) ||
98                 (size= EulerObject_Check(value)      ? 3 : 0) ||
99                 (size= QuaternionObject_Check(value) ? 4 : 0) ||
100                 (size= ColorObject_Check(value)      ? 3 : 0))
101         {
102                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
103                         return -1;
104                 }
105
106                 if(size > array_max || size < array_min) {
107                         if (array_max == array_min)     {
108                                 PyErr_Format(PyExc_ValueError,
109                                              "%.200s: sequence size is %d, expected %d",
110                                              error_prefix, size, array_max);
111                         }
112                         else {
113                                 PyErr_Format(PyExc_ValueError,
114                                              "%.200s: sequence size is %d, expected [%d - %d]",
115                                              error_prefix, size, array_min, array_max);
116                         }
117                         return -1;
118                 }
119
120                 memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
121                 return size;
122         }
123         else
124 #endif
125         {
126                 return mathutils_array_parse_fast(array, array_min, array_max, value, error_prefix);
127         }
128 }
129
130 int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
131 {
132         if(EulerObject_Check(value)) {
133                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
134                         return -1;
135                 }
136                 else {
137                         eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
138                         return 0;
139                 }
140         }
141         else if (QuaternionObject_Check(value)) {
142                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
143                         return -1;
144                 }
145                 else {
146                         float tquat[4];
147                         normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
148                         quat_to_mat3(rmat, tquat);
149                         return 0;
150                 }
151         }
152         else if (MatrixObject_Check(value)) {
153                 if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
154                         return -1;
155                 }
156                 else if(((MatrixObject *)value)->col_size < 3 || ((MatrixObject *)value)->row_size < 3) {
157                         PyErr_Format(PyExc_ValueError,
158                                      "%.200s: matrix must have minimum 3x3 dimensions",
159                                      error_prefix);
160                         return -1;
161                 }
162                 else {
163                         matrix_as_3x3(rmat, (MatrixObject *)value);
164                         normalize_m3(rmat);
165                         return 0;
166                 }
167         }
168         else {
169                 PyErr_Format(PyExc_TypeError,
170                              "%.200s: expected a Euler, Quaternion or Matrix type, "
171                              "found %.200s", error_prefix, Py_TYPE(value)->tp_name);
172                 return -1;
173         }
174 }
175
176
177 //----------------------------------MATRIX FUNCTIONS--------------------
178
179
180 /* Utility functions */
181
182 // LomontRRDCompare4, Ever Faster Float Comparisons by Randy Dillon
183 #define SIGNMASK(i) (-(int)(((unsigned int)(i))>>31))
184
185 int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
186 {       // solid, fast routine across all platforms
187         // with constant time behavior
188         int ai = *(int *)(&af);
189         int bi = *(int *)(&bf);
190         int test = SIGNMASK(ai^bi);
191         int diff, v1, v2;
192
193         assert((0 == test) || (0xFFFFFFFF == test));
194         diff = (ai ^ (test & 0x7fffffff)) - bi;
195         v1 = maxDiff + diff;
196         v2 = maxDiff - diff;
197         return (v1|v2) >= 0;
198 }
199
200 /*---------------------- EXPP_VectorsAreEqual -------------------------
201   Builds on EXPP_FloatsAreEqual to test vectors */
202 int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
203 {
204         int x;
205         for (x=0; x< size; x++){
206                 if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
207                         return 0;
208         }
209         return 1;
210 }
211
212
213 /* Mathutils Callbacks */
214
215 /* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
216 static Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
217
218 int Mathutils_RegisterCallback(Mathutils_Callback *cb)
219 {
220         int i;
221         
222         /* find the first free slot */
223         for(i= 0; mathutils_callbacks[i]; i++) {
224                 if(mathutils_callbacks[i]==cb) /* already registered? */
225                         return i;
226         }
227         
228         mathutils_callbacks[i] = cb;
229         return i;
230 }
231
232 /* use macros to check for NULL */
233 int _BaseMathObject_ReadCallback(BaseMathObject *self)
234 {
235         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
236         if(cb->get(self, self->cb_subtype) != -1)
237                 return 0;
238
239         if(!PyErr_Occurred()) {
240                 PyErr_Format(PyExc_RuntimeError,
241                              "%s read, user has become invalid",
242                              Py_TYPE(self)->tp_name);
243         }
244         return -1;
245 }
246
247 int _BaseMathObject_WriteCallback(BaseMathObject *self)
248 {
249         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
250         if(cb->set(self, self->cb_subtype) != -1)
251                 return 0;
252
253         if(!PyErr_Occurred()) {
254                 PyErr_Format(PyExc_RuntimeError,
255                              "%s write, user has become invalid",
256                              Py_TYPE(self)->tp_name);
257         }
258         return -1;
259 }
260
261 int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
262 {
263         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
264         if(cb->get_index(self, self->cb_subtype, index) != -1)
265                 return 0;
266
267         if(!PyErr_Occurred()) {
268                 PyErr_Format(PyExc_RuntimeError,
269                              "%s read index, user has become invalid",
270                              Py_TYPE(self)->tp_name);
271         }
272         return -1;
273 }
274
275 int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
276 {
277         Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
278         if(cb->set_index(self, self->cb_subtype, index) != -1)
279                 return 0;
280
281         if(!PyErr_Occurred()) {
282                 PyErr_Format(PyExc_RuntimeError,
283                              "%s write index, user has become invalid",
284                              Py_TYPE(self)->tp_name);
285         }
286         return -1;
287 }
288
289 /* BaseMathObject generic functions for all mathutils types */
290 char BaseMathObject_Owner_doc[] = "The item this is wrapping or None  (readonly).";
291 PyObject *BaseMathObject_getOwner(BaseMathObject *self, void *UNUSED(closure))
292 {
293         PyObject *ret= self->cb_user ? self->cb_user : Py_None;
294         Py_INCREF(ret);
295         return ret;
296 }
297
298 char BaseMathObject_Wrapped_doc[] = "True when this object wraps external data (readonly).\n\n:type: boolean";
299 PyObject *BaseMathObject_getWrapped(BaseMathObject *self, void *UNUSED(closure))
300 {
301         return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0);
302 }
303
304 int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
305 {
306         Py_VISIT(self->cb_user);
307         return 0;
308 }
309
310 int BaseMathObject_clear(BaseMathObject *self)
311 {
312         Py_CLEAR(self->cb_user);
313         return 0;
314 }
315
316 void BaseMathObject_dealloc(BaseMathObject *self)
317 {
318         /* only free non wrapped */
319         if(self->wrapped != Py_WRAP) {
320                 PyMem_Free(self->data);
321         }
322
323         if(self->cb_user) {
324                 PyObject_GC_UnTrack(self);
325                 BaseMathObject_clear(self);
326         }
327
328         Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
329 }
330
331 /*----------------------------MODULE INIT-------------------------*/
332 static struct PyMethodDef M_Mathutils_methods[] = {
333         {NULL, NULL, 0, NULL}
334 };
335
336 static struct PyModuleDef M_Mathutils_module_def = {
337         PyModuleDef_HEAD_INIT,
338         "mathutils",  /* m_name */
339         M_Mathutils_doc,  /* m_doc */
340         0,  /* m_size */
341         M_Mathutils_methods,  /* m_methods */
342         NULL,  /* m_reload */
343         NULL,  /* m_traverse */
344         NULL,  /* m_clear */
345         NULL,  /* m_free */
346 };
347
348 PyMODINIT_FUNC PyInit_mathutils(void)
349 {
350         PyObject *submodule;
351         PyObject *item;
352
353         if(PyType_Ready(&vector_Type) < 0)
354                 return NULL;
355         if(PyType_Ready(&matrix_Type) < 0)
356                 return NULL;    
357         if(PyType_Ready(&euler_Type) < 0)
358                 return NULL;
359         if(PyType_Ready(&quaternion_Type) < 0)
360                 return NULL;
361         if(PyType_Ready(&color_Type) < 0)
362                 return NULL;
363
364         submodule = PyModule_Create(&M_Mathutils_module_def);
365         
366         /* each type has its own new() function */
367         PyModule_AddObject(submodule, "Vector",         (PyObject *)&vector_Type);
368         PyModule_AddObject(submodule, "Matrix",         (PyObject *)&matrix_Type);
369         PyModule_AddObject(submodule, "Euler",          (PyObject *)&euler_Type);
370         PyModule_AddObject(submodule, "Quaternion",     (PyObject *)&quaternion_Type);
371         PyModule_AddObject(submodule, "Color",          (PyObject *)&color_Type);
372         
373         /* submodule */
374         PyModule_AddObject(submodule, "geometry",               (item=PyInit_mathutils_geometry()));
375         /* XXX, python doesnt do imports with this usefully yet
376          * 'from mathutils.geometry import PolyFill'
377          * ...fails without this. */
378         PyDict_SetItemString(PyThreadState_GET()->interp->modules, "mathutils.geometry", item);
379         Py_INCREF(item);
380
381         mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
382
383         return submodule;
384 }