2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Joseph Gilbert, Campbell Barton
20 * ***** END GPL LICENSE BLOCK *****
23 /** \file blender/python/mathutils/mathutils.c
24 * \ingroup pymathutils
29 #include "mathutils.h"
32 #include "BLI_utildefines.h"
34 #ifndef MATH_STANDALONE
35 # include "BLI_dynstr.h"
38 PyDoc_STRVAR(M_Mathutils_doc,
39 "This module provides access to matrices, eulers, quaternions and vectors."
41 static int mathutils_array_parse_fast(float *array,
44 const char *error_prefix)
53 if (((array[i] = PyFloat_AsDouble((item = PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0f) &&
56 PyErr_Format(PyExc_TypeError,
57 "%.200s: sequence index %d expected a number, "
58 "found '%.200s' type, ",
59 error_prefix, i, Py_TYPE(item)->tp_name);
60 Py_DECREF(value_fast);
65 Py_XDECREF(value_fast);
69 /* helper functionm returns length of the 'value', -1 on error */
70 int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
74 #if 1 /* approx 6x speedup for mathutils types */
76 if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
77 (size = EulerObject_Check(value) ? 3 : 0) ||
78 (size = QuaternionObject_Check(value) ? 4 : 0) ||
79 (size = ColorObject_Check(value) ? 3 : 0))
81 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
85 if (size > array_max || size < array_min) {
86 if (array_max == array_min) {
87 PyErr_Format(PyExc_ValueError,
88 "%.200s: sequence size is %d, expected %d",
89 error_prefix, size, array_max);
92 PyErr_Format(PyExc_ValueError,
93 "%.200s: sequence size is %d, expected [%d - %d]",
94 error_prefix, size, array_min, array_max);
99 memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
105 PyObject *value_fast = NULL;
107 /* non list/tuple cases */
108 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
109 /* PySequence_Fast sets the error */
113 size = PySequence_Fast_GET_SIZE(value_fast);
115 if (size > array_max || size < array_min) {
116 if (array_max == array_min) {
117 PyErr_Format(PyExc_ValueError,
118 "%.200s: sequence size is %d, expected %d",
119 error_prefix, size, array_max);
122 PyErr_Format(PyExc_ValueError,
123 "%.200s: sequence size is %d, expected [%d - %d]",
124 error_prefix, size, array_min, array_max);
126 Py_DECREF(value_fast);
130 return mathutils_array_parse_fast(array, size, value_fast, error_prefix);
134 /* on error, -1 is returned and no allocation is made */
135 int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix)
139 #if 1 /* approx 6x speedup for mathutils types */
141 if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
142 (size = EulerObject_Check(value) ? 3 : 0) ||
143 (size = QuaternionObject_Check(value) ? 4 : 0) ||
144 (size = ColorObject_Check(value) ? 3 : 0))
146 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
150 if (size < array_min) {
151 PyErr_Format(PyExc_ValueError,
152 "%.200s: sequence size is %d, expected > %d",
153 error_prefix, size, array_min);
157 *array = PyMem_Malloc(size * sizeof(float));
158 memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
164 PyObject *value_fast = NULL;
168 /* non list/tuple cases */
169 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
170 /* PySequence_Fast sets the error */
174 size = PySequence_Fast_GET_SIZE(value_fast);
176 if (size < array_min) {
177 PyErr_Format(PyExc_ValueError,
178 "%.200s: sequence size is %d, expected > %d",
179 error_prefix, size, array_min);
183 *array = PyMem_Malloc(size * sizeof(float));
185 ret = mathutils_array_parse_fast(*array, size, value_fast, error_prefix);
195 /* parse an array of vectors */
196 int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix)
198 PyObject *value_fast = NULL;
201 /* non list/tuple cases */
202 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
203 /* PySequence_Fast sets the error */
207 size = PySequence_Fast_GET_SIZE(value_fast);
212 fp = *array = PyMem_Malloc(size * array_dim * sizeof(float));
214 for (i = 0; i < size; i++, fp += array_dim) {
215 PyObject *item = PySequence_Fast_GET_ITEM(value, i);
217 if (mathutils_array_parse(fp, array_dim, array_dim, item, error_prefix) == -1) {
226 Py_DECREF(value_fast);
230 int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
232 if (EulerObject_Check(value)) {
233 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
237 eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
241 else if (QuaternionObject_Check(value)) {
242 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
247 normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
248 quat_to_mat3(rmat, tquat);
252 else if (MatrixObject_Check(value)) {
253 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
256 else if (((MatrixObject *)value)->num_row < 3 || ((MatrixObject *)value)->num_col < 3) {
257 PyErr_Format(PyExc_ValueError,
258 "%.200s: matrix must have minimum 3x3 dimensions",
263 matrix_as_3x3(rmat, (MatrixObject *)value);
269 PyErr_Format(PyExc_TypeError,
270 "%.200s: expected a Euler, Quaternion or Matrix type, "
271 "found %.200s", error_prefix, Py_TYPE(value)->tp_name);
277 /* ----------------------------------MATRIX FUNCTIONS-------------------- */
280 /* Utility functions */
282 /* LomontRRDCompare4, Ever Faster Float Comparisons by Randy Dillon */
283 #define SIGNMASK(i) (-(int)(((unsigned int)(i)) >> 31))
285 int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
287 /* solid, fast routine across all platforms
288 * with constant time behavior */
289 int ai = *(int *)(&af);
290 int bi = *(int *)(&bf);
291 int test = SIGNMASK(ai ^ bi);
294 assert((0 == test) || (0xFFFFFFFF == test));
295 diff = (ai ^ (test & 0x7fffffff)) - bi;
298 return (v1 | v2) >= 0;
301 /*---------------------- EXPP_VectorsAreEqual -------------------------
302 * Builds on EXPP_FloatsAreEqual to test vectors */
303 int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
306 for (x = 0; x < size; x++) {
307 if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
313 #ifndef MATH_STANDALONE
314 /* dynstr as python string utility funcions, frees 'ds'! */
315 PyObject *mathutils_dynstr_to_py(struct DynStr *ds)
317 const int ds_len = BLI_dynstr_get_len(ds); /* space for \0 */
318 char *ds_buf = PyMem_Malloc(ds_len + 1);
320 BLI_dynstr_get_cstring_ex(ds, ds_buf);
322 ret = PyUnicode_FromStringAndSize(ds_buf, ds_len);
328 /* silly function, we dont use arg. just check its compatible with __deepcopy__ */
329 int mathutils_deepcopy_args_check(PyObject *args)
331 PyObject *dummy_pydict;
332 return PyArg_ParseTuple(args, "|O!:__deepcopy__", &PyDict_Type, &dummy_pydict) != 0;
335 /* Mathutils Callbacks */
337 /* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
338 #define MATHUTILS_TOT_CB 16
339 static Mathutils_Callback *mathutils_callbacks[MATHUTILS_TOT_CB] = {NULL};
341 unsigned char Mathutils_RegisterCallback(Mathutils_Callback *cb)
345 /* find the first free slot */
346 for (i = 0; mathutils_callbacks[i]; i++) {
347 if (mathutils_callbacks[i] == cb) /* already registered? */
351 BLI_assert(i + 1 < MATHUTILS_TOT_CB);
353 mathutils_callbacks[i] = cb;
357 /* use macros to check for NULL */
358 int _BaseMathObject_ReadCallback(BaseMathObject *self)
360 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
361 if (LIKELY(cb->get(self, self->cb_subtype) != -1)) {
365 if (!PyErr_Occurred()) {
366 PyErr_Format(PyExc_RuntimeError,
367 "%s read, user has become invalid",
368 Py_TYPE(self)->tp_name);
373 int _BaseMathObject_WriteCallback(BaseMathObject *self)
375 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
376 if (LIKELY(cb->set(self, self->cb_subtype) != -1)) {
380 if (!PyErr_Occurred()) {
381 PyErr_Format(PyExc_RuntimeError,
382 "%s write, user has become invalid",
383 Py_TYPE(self)->tp_name);
388 int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
390 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
391 if (LIKELY(cb->get_index(self, self->cb_subtype, index) != -1)) {
395 if (!PyErr_Occurred()) {
396 PyErr_Format(PyExc_RuntimeError,
397 "%s read index, user has become invalid",
398 Py_TYPE(self)->tp_name);
403 int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
405 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
406 if (LIKELY(cb->set_index(self, self->cb_subtype, index) != -1)) {
410 if (!PyErr_Occurred()) {
411 PyErr_Format(PyExc_RuntimeError,
412 "%s write index, user has become invalid",
413 Py_TYPE(self)->tp_name);
418 /* BaseMathObject generic functions for all mathutils types */
419 char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only).";
420 PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
422 PyObject *ret = self->cb_user ? self->cb_user : Py_None;
427 char BaseMathObject_is_wrapped_doc[] = "True when this object wraps external data (read-only).\n\n:type: boolean";
428 PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure))
430 return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1 : 0);
433 int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
435 Py_VISIT(self->cb_user);
439 int BaseMathObject_clear(BaseMathObject *self)
441 Py_CLEAR(self->cb_user);
445 void BaseMathObject_dealloc(BaseMathObject *self)
447 /* only free non wrapped */
448 if (self->wrapped != Py_WRAP) {
449 PyMem_Free(self->data);
453 PyObject_GC_UnTrack(self);
454 BaseMathObject_clear(self);
457 Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
460 /*----------------------------MODULE INIT-------------------------*/
461 static struct PyMethodDef M_Mathutils_methods[] = {
462 {NULL, NULL, 0, NULL}
465 static struct PyModuleDef M_Mathutils_module_def = {
466 PyModuleDef_HEAD_INIT,
467 "mathutils", /* m_name */
468 M_Mathutils_doc, /* m_doc */
470 M_Mathutils_methods, /* m_methods */
472 NULL, /* m_traverse */
478 /* submodules only */
479 #include "mathutils_geometry.h"
480 #include "mathutils_kdtree.h"
481 #include "mathutils_noise.h"
483 PyMODINIT_FUNC PyInit_mathutils(void)
487 PyObject *sys_modules = PyThreadState_GET()->interp->modules;
489 if (PyType_Ready(&vector_Type) < 0)
491 if (PyType_Ready(&matrix_Type) < 0)
493 if (PyType_Ready(&matrix_access_Type) < 0)
495 if (PyType_Ready(&euler_Type) < 0)
497 if (PyType_Ready(&quaternion_Type) < 0)
499 if (PyType_Ready(&color_Type) < 0)
502 mod = PyModule_Create(&M_Mathutils_module_def);
504 /* each type has its own new() function */
505 PyModule_AddObject(mod, vector_Type.tp_name, (PyObject *)&vector_Type);
506 PyModule_AddObject(mod, matrix_Type.tp_name, (PyObject *)&matrix_Type);
507 PyModule_AddObject(mod, euler_Type.tp_name, (PyObject *)&euler_Type);
508 PyModule_AddObject(mod, quaternion_Type.tp_name, (PyObject *)&quaternion_Type);
509 PyModule_AddObject(mod, color_Type.tp_name, (PyObject *)&color_Type);
512 PyModule_AddObject(mod, "geometry", (submodule = PyInit_mathutils_geometry()));
513 /* XXX, python doesnt do imports with this usefully yet
514 * 'from mathutils.geometry import PolyFill'
515 * ...fails without this. */
516 PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
517 Py_INCREF(submodule);
519 #ifndef MATH_STANDALONE
520 /* Noise submodule */
521 PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
522 PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
523 Py_INCREF(submodule);
525 /* KDTree submodule */
526 PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree()));
527 PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
528 Py_INCREF(submodule);
531 mathutils_matrix_row_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_row_cb);
532 mathutils_matrix_col_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_col_cb);
533 mathutils_matrix_translation_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_translation_cb);