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
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19
* All rights reserved.
21
* This is a new part of Blender.
23
* Contributor(s): Joseph Gilbert, Campbell Barton
25
* ***** END GPL LICENSE BLOCK *****
28
/** \file blender/python/mathutils/mathutils.c
29
* \ingroup pymathutils
34
#include "mathutils.h"
37
#include "BLI_utildefines.h"
38
#include "BLI_dynstr.h"
40
PyDoc_STRVAR(M_Mathutils_doc,
41
"This module provides access to matrices, eulers, quaternions and vectors."
43
static int mathutils_array_parse_fast(float *array,
46
const char *error_prefix)
55
if (((array[i] = PyFloat_AsDouble((item = PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0f) &&
58
PyErr_Format(PyExc_TypeError,
59
"%.200s: sequence index %d expected a number, "
60
"found '%.200s' type, ",
61
error_prefix, i, Py_TYPE(item)->tp_name);
62
Py_DECREF(value_fast);
67
Py_XDECREF(value_fast);
71
/* helper functionm returns length of the 'value', -1 on error */
72
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
76
#if 1 /* approx 6x speedup for mathutils types */
78
if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
79
(size = EulerObject_Check(value) ? 3 : 0) ||
80
(size = QuaternionObject_Check(value) ? 4 : 0) ||
81
(size = ColorObject_Check(value) ? 3 : 0))
83
if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
87
if (size > array_max || size < array_min) {
88
if (array_max == array_min) {
89
PyErr_Format(PyExc_ValueError,
90
"%.200s: sequence size is %d, expected %d",
91
error_prefix, size, array_max);
94
PyErr_Format(PyExc_ValueError,
95
"%.200s: sequence size is %d, expected [%d - %d]",
96
error_prefix, size, array_min, array_max);
101
memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
107
PyObject *value_fast = NULL;
109
/* non list/tuple cases */
110
if (!(value_fast = PySequence_Fast(value, error_prefix))) {
111
/* PySequence_Fast sets the error */
115
size = PySequence_Fast_GET_SIZE(value_fast);
117
if (size > array_max || size < array_min) {
118
if (array_max == array_min) {
119
PyErr_Format(PyExc_ValueError,
120
"%.200s: sequence size is %d, expected %d",
121
error_prefix, size, array_max);
124
PyErr_Format(PyExc_ValueError,
125
"%.200s: sequence size is %d, expected [%d - %d]",
126
error_prefix, size, array_min, array_max);
128
Py_DECREF(value_fast);
132
return mathutils_array_parse_fast(array, size, value_fast, error_prefix);
136
int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix)
140
#if 1 /* approx 6x speedup for mathutils types */
142
if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
143
(size = EulerObject_Check(value) ? 3 : 0) ||
144
(size = QuaternionObject_Check(value) ? 4 : 0) ||
145
(size = ColorObject_Check(value) ? 3 : 0))
147
if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
151
if (size < array_min) {
152
PyErr_Format(PyExc_ValueError,
153
"%.200s: sequence size is %d, expected > %d",
154
error_prefix, size, array_min);
158
*array = PyMem_Malloc(size * sizeof(float));
159
memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
165
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
return mathutils_array_parse_fast(*array, size, value_fast, error_prefix);
189
/* parse an array of vectors */
190
int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix)
192
PyObject *value_fast = NULL;
195
/* non list/tuple cases */
196
if (!(value_fast = PySequence_Fast(value, error_prefix))) {
197
/* PySequence_Fast sets the error */
201
size = PySequence_Fast_GET_SIZE(value_fast);
206
fp = *array = PyMem_Malloc(size * array_dim * sizeof(float));
208
for (i = 0; i < size; i++, fp += array_dim) {
209
PyObject *item = PySequence_Fast_GET_ITEM(value, i);
211
if (mathutils_array_parse(fp, array_dim, array_dim, item, error_prefix) == -1) {
220
Py_DECREF(value_fast);
224
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
226
if (EulerObject_Check(value)) {
227
if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
231
eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
235
else if (QuaternionObject_Check(value)) {
236
if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
241
normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
242
quat_to_mat3(rmat, tquat);
246
else if (MatrixObject_Check(value)) {
247
if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
250
else if (((MatrixObject *)value)->num_row < 3 || ((MatrixObject *)value)->num_col < 3) {
251
PyErr_Format(PyExc_ValueError,
252
"%.200s: matrix must have minimum 3x3 dimensions",
257
matrix_as_3x3(rmat, (MatrixObject *)value);
263
PyErr_Format(PyExc_TypeError,
264
"%.200s: expected a Euler, Quaternion or Matrix type, "
265
"found %.200s", error_prefix, Py_TYPE(value)->tp_name);
271
//----------------------------------MATRIX FUNCTIONS--------------------
274
/* Utility functions */
276
// LomontRRDCompare4, Ever Faster Float Comparisons by Randy Dillon
277
#define SIGNMASK(i) (-(int)(((unsigned int)(i)) >> 31))
279
int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
281
/* solid, fast routine across all platforms
282
* with constant time behavior */
283
int ai = *(int *)(&af);
284
int bi = *(int *)(&bf);
285
int test = SIGNMASK(ai ^ bi);
288
assert((0 == test) || (0xFFFFFFFF == test));
289
diff = (ai ^ (test & 0x7fffffff)) - bi;
292
return (v1 | v2) >= 0;
295
/*---------------------- EXPP_VectorsAreEqual -------------------------
296
* Builds on EXPP_FloatsAreEqual to test vectors */
297
int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
300
for (x = 0; x < size; x++) {
301
if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
307
/* dynstr as python string utility funcions, frees 'ds'! */
308
PyObject *mathutils_dynstr_to_py(struct DynStr *ds)
310
const int ds_len = BLI_dynstr_get_len(ds); /* space for \0 */
311
char *ds_buf = PyMem_Malloc(ds_len + 1);
313
BLI_dynstr_get_cstring_ex(ds, ds_buf);
315
ret = PyUnicode_FromStringAndSize(ds_buf, ds_len);
320
/* silly function, we dont use arg. just check its compatible with __deepcopy__ */
321
int mathutils_deepcopy_args_check(PyObject *args)
323
PyObject *dummy_pydict;
324
return PyArg_ParseTuple(args, "|O!:__deepcopy__", &PyDict_Type, &dummy_pydict) != 0;
327
/* Mathutils Callbacks */
329
/* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
330
#define MATHUTILS_TOT_CB 10
331
static Mathutils_Callback *mathutils_callbacks[MATHUTILS_TOT_CB] = {NULL};
333
unsigned char Mathutils_RegisterCallback(Mathutils_Callback *cb)
337
/* find the first free slot */
338
for (i = 0; mathutils_callbacks[i]; i++) {
339
if (mathutils_callbacks[i] == cb) /* already registered? */
343
BLI_assert(i + 1 < MATHUTILS_TOT_CB);
345
mathutils_callbacks[i] = cb;
349
/* use macros to check for NULL */
350
int _BaseMathObject_ReadCallback(BaseMathObject *self)
352
Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
353
if (LIKELY(cb->get(self, self->cb_subtype) != -1)) {
357
if (!PyErr_Occurred()) {
358
PyErr_Format(PyExc_RuntimeError,
359
"%s read, user has become invalid",
360
Py_TYPE(self)->tp_name);
365
int _BaseMathObject_WriteCallback(BaseMathObject *self)
367
Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
368
if (LIKELY(cb->set(self, self->cb_subtype) != -1)) {
372
if (!PyErr_Occurred()) {
373
PyErr_Format(PyExc_RuntimeError,
374
"%s write, user has become invalid",
375
Py_TYPE(self)->tp_name);
380
int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
382
Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
383
if (LIKELY(cb->get_index(self, self->cb_subtype, index) != -1)) {
387
if (!PyErr_Occurred()) {
388
PyErr_Format(PyExc_RuntimeError,
389
"%s read index, user has become invalid",
390
Py_TYPE(self)->tp_name);
395
int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
397
Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
398
if (LIKELY(cb->set_index(self, self->cb_subtype, index) != -1)) {
402
if (!PyErr_Occurred()) {
403
PyErr_Format(PyExc_RuntimeError,
404
"%s write index, user has become invalid",
405
Py_TYPE(self)->tp_name);
410
/* BaseMathObject generic functions for all mathutils types */
411
char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only).";
412
PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
414
PyObject *ret = self->cb_user ? self->cb_user : Py_None;
419
char BaseMathObject_is_wrapped_doc[] = "True when this object wraps external data (read-only).\n\n:type: boolean";
420
PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure))
422
return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1 : 0);
425
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
427
Py_VISIT(self->cb_user);
431
int BaseMathObject_clear(BaseMathObject *self)
433
Py_CLEAR(self->cb_user);
437
void BaseMathObject_dealloc(BaseMathObject *self)
439
/* only free non wrapped */
440
if (self->wrapped != Py_WRAP) {
441
PyMem_Free(self->data);
445
PyObject_GC_UnTrack(self);
446
BaseMathObject_clear(self);
449
Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
452
/*----------------------------MODULE INIT-------------------------*/
453
static struct PyMethodDef M_Mathutils_methods[] = {
454
{NULL, NULL, 0, NULL}
457
static struct PyModuleDef M_Mathutils_module_def = {
458
PyModuleDef_HEAD_INIT,
459
"mathutils", /* m_name */
460
M_Mathutils_doc, /* m_doc */
462
M_Mathutils_methods, /* m_methods */
464
NULL, /* m_traverse */
469
PyMODINIT_FUNC PyInit_mathutils(void)
473
PyObject *sys_modules = PyThreadState_GET()->interp->modules;
475
if (PyType_Ready(&vector_Type) < 0)
477
if (PyType_Ready(&matrix_Type) < 0)
479
if (PyType_Ready(&matrix_access_Type) < 0)
481
if (PyType_Ready(&euler_Type) < 0)
483
if (PyType_Ready(&quaternion_Type) < 0)
485
if (PyType_Ready(&color_Type) < 0)
488
mod = PyModule_Create(&M_Mathutils_module_def);
490
/* each type has its own new() function */
491
PyModule_AddObject(mod, vector_Type.tp_name, (PyObject *)&vector_Type);
492
PyModule_AddObject(mod, matrix_Type.tp_name, (PyObject *)&matrix_Type);
493
PyModule_AddObject(mod, euler_Type.tp_name, (PyObject *)&euler_Type);
494
PyModule_AddObject(mod, quaternion_Type.tp_name, (PyObject *)&quaternion_Type);
495
PyModule_AddObject(mod, color_Type.tp_name, (PyObject *)&color_Type);
498
PyModule_AddObject(mod, "geometry", (submodule = PyInit_mathutils_geometry()));
499
/* XXX, python doesnt do imports with this usefully yet
500
* 'from mathutils.geometry import PolyFill'
501
* ...fails without this. */
502
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
503
Py_INCREF(submodule);
505
/* Noise submodule */
506
PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
507
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
508
Py_INCREF(submodule);
510
mathutils_matrix_row_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_row_cb);
511
mathutils_matrix_col_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_col_cb);
512
mathutils_matrix_translation_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_translation_cb);