1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup pymathutils
19 */
20
21 #include <Python.h>
22
23 #include "mathutils.h"
24
25 #include "BLI_math.h"
26 #include "BLI_utildefines.h"
27
28 #include "../generic/py_capi_utils.h"
29 #include "../generic/python_utildefines.h"
30
31 #ifndef MATH_STANDALONE
32 # include "BLI_dynstr.h"
33 #endif
34
35 PyDoc_STRVAR(
36 M_Mathutils_doc,
37 "This module provides access to math operations.\n"
38 "\n"
39 ".. note::\n"
40 "\n"
41 " Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
42 " such as tuples, lists.\n"
43 "\n"
44 "The :mod:`mathutils` module provides the following classes:\n"
45 "\n"
46 "- :class:`Color`,\n"
47 "- :class:`Euler`,\n"
48 "- :class:`Matrix`,\n"
49 "- :class:`Quaternion`,\n"
50 "- :class:`Vector`,\n");
mathutils_array_parse_fast(float * array,int size,PyObject * value_fast,const char * error_prefix)51 static int mathutils_array_parse_fast(float *array,
52 int size,
53 PyObject *value_fast,
54 const char *error_prefix)
55 {
56 PyObject *item;
57 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
58
59 int i;
60
61 i = size;
62 do {
63 i--;
64 if (((array[i] = PyFloat_AsDouble((item = value_fast_items[i]))) == -1.0f) &&
65 PyErr_Occurred()) {
66 PyErr_Format(PyExc_TypeError,
67 "%.200s: sequence index %d expected a number, "
68 "found '%.200s' type, ",
69 error_prefix,
70 i,
71 Py_TYPE(item)->tp_name);
72 size = -1;
73 break;
74 }
75 } while (i);
76
77 return size;
78 }
79
80 /**
81 * helper function that returns a Python ``__hash__``.
82 *
83 * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
84 */
mathutils_array_hash(const float * array,size_t array_len)85 Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
86 {
87 int i;
88 Py_uhash_t x; /* Unsigned for defined overflow behavior. */
89 Py_hash_t y;
90 Py_uhash_t mult;
91 Py_ssize_t len;
92
93 mult = _PyHASH_MULTIPLIER;
94 len = array_len;
95 x = 0x345678UL;
96 i = 0;
97 while (--len >= 0) {
98 y = _Py_HashDouble((double)(array[i++]));
99 if (y == -1) {
100 return -1;
101 }
102 x = (x ^ y) * mult;
103 /* the cast might truncate len; that doesn't change hash stability */
104 mult += (Py_hash_t)(82520UL + len + len);
105 }
106 x += 97531UL;
107 if (x == (Py_uhash_t)-1) {
108 x = -2;
109 }
110 return x;
111 }
112
113 /* helper function returns length of the 'value', -1 on error */
mathutils_array_parse(float * array,int array_min,int array_max,PyObject * value,const char * error_prefix)114 int mathutils_array_parse(
115 float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
116 {
117 const uint flag = array_max;
118 int size;
119
120 array_max &= ~MU_ARRAY_FLAGS;
121
122 #if 1 /* approx 6x speedup for mathutils types */
123
124 if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
125 (size = EulerObject_Check(value) ? 3 : 0) ||
126 (size = QuaternionObject_Check(value) ? 4 : 0) ||
127 (size = ColorObject_Check(value) ? 3 : 0)) {
128 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
129 return -1;
130 }
131
132 if (flag & MU_ARRAY_SPILL) {
133 CLAMP_MAX(size, array_max);
134 }
135
136 if (size > array_max || size < array_min) {
137 if (array_max == array_min) {
138 PyErr_Format(PyExc_ValueError,
139 "%.200s: sequence size is %d, expected %d",
140 error_prefix,
141 size,
142 array_max);
143 }
144 else {
145 PyErr_Format(PyExc_ValueError,
146 "%.200s: sequence size is %d, expected [%d - %d]",
147 error_prefix,
148 size,
149 array_min,
150 array_max);
151 }
152 return -1;
153 }
154
155 memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
156 }
157 else
158 #endif
159 {
160 PyObject *value_fast = NULL;
161
162 /* non list/tuple cases */
163 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
164 /* PySequence_Fast sets the error */
165 return -1;
166 }
167
168 size = PySequence_Fast_GET_SIZE(value_fast);
169
170 if (flag & MU_ARRAY_SPILL) {
171 CLAMP_MAX(size, array_max);
172 }
173
174 if (size > array_max || size < array_min) {
175 if (array_max == array_min) {
176 PyErr_Format(PyExc_ValueError,
177 "%.200s: sequence size is %d, expected %d",
178 error_prefix,
179 size,
180 array_max);
181 }
182 else {
183 PyErr_Format(PyExc_ValueError,
184 "%.200s: sequence size is %d, expected [%d - %d]",
185 error_prefix,
186 size,
187 array_min,
188 array_max);
189 }
190 Py_DECREF(value_fast);
191 return -1;
192 }
193
194 size = mathutils_array_parse_fast(array, size, value_fast, error_prefix);
195 Py_DECREF(value_fast);
196 }
197
198 if (size != -1) {
199 if (flag & MU_ARRAY_ZERO) {
200 const int size_left = array_max - size;
201 if (size_left) {
202 memset(&array[size], 0, sizeof(float) * size_left);
203 }
204 }
205 }
206
207 return size;
208 }
209
210 /* on error, -1 is returned and no allocation is made */
mathutils_array_parse_alloc(float ** array,int array_min,PyObject * value,const char * error_prefix)211 int mathutils_array_parse_alloc(float **array,
212 int array_min,
213 PyObject *value,
214 const char *error_prefix)
215 {
216 int size;
217
218 #if 1 /* approx 6x speedup for mathutils types */
219
220 if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
221 (size = EulerObject_Check(value) ? 3 : 0) ||
222 (size = QuaternionObject_Check(value) ? 4 : 0) ||
223 (size = ColorObject_Check(value) ? 3 : 0)) {
224 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
225 return -1;
226 }
227
228 if (size < array_min) {
229 PyErr_Format(PyExc_ValueError,
230 "%.200s: sequence size is %d, expected > %d",
231 error_prefix,
232 size,
233 array_min);
234 return -1;
235 }
236
237 *array = PyMem_Malloc(size * sizeof(float));
238 memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
239 return size;
240 }
241
242 #endif
243
244 PyObject *value_fast = NULL;
245 // *array = NULL;
246 int ret;
247
248 /* non list/tuple cases */
249 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
250 /* PySequence_Fast sets the error */
251 return -1;
252 }
253
254 size = PySequence_Fast_GET_SIZE(value_fast);
255
256 if (size < array_min) {
257 Py_DECREF(value_fast);
258 PyErr_Format(PyExc_ValueError,
259 "%.200s: sequence size is %d, expected > %d",
260 error_prefix,
261 size,
262 array_min);
263 return -1;
264 }
265
266 *array = PyMem_Malloc(size * sizeof(float));
267
268 ret = mathutils_array_parse_fast(*array, size, value_fast, error_prefix);
269 Py_DECREF(value_fast);
270
271 if (ret == -1) {
272 PyMem_Free(*array);
273 }
274
275 return ret;
276 }
277
278 /* parse an array of vectors */
mathutils_array_parse_alloc_v(float ** array,int array_dim,PyObject * value,const char * error_prefix)279 int mathutils_array_parse_alloc_v(float **array,
280 int array_dim,
281 PyObject *value,
282 const char *error_prefix)
283 {
284 PyObject *value_fast;
285 const int array_dim_flag = array_dim;
286 int i, size;
287
288 /* non list/tuple cases */
289 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
290 /* PySequence_Fast sets the error */
291 return -1;
292 }
293
294 size = PySequence_Fast_GET_SIZE(value_fast);
295
296 if (size != 0) {
297 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
298 float *fp;
299
300 array_dim &= ~MU_ARRAY_FLAGS;
301
302 fp = *array = PyMem_Malloc(size * array_dim * sizeof(float));
303
304 for (i = 0; i < size; i++, fp += array_dim) {
305 PyObject *item = value_fast_items[i];
306
307 if (mathutils_array_parse(fp, array_dim, array_dim_flag, item, error_prefix) == -1) {
308 PyMem_Free(*array);
309 *array = NULL;
310 size = -1;
311 break;
312 }
313 }
314 }
315
316 Py_DECREF(value_fast);
317 return size;
318 }
319
320 /* Parse an sequence array_dim integers into array. */
mathutils_int_array_parse(int * array,int array_dim,PyObject * value,const char * error_prefix)321 int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const char *error_prefix)
322 {
323 int size, i;
324 PyObject *value_fast, **value_fast_items, *item;
325
326 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
327 /* PySequence_Fast sets the error */
328 return -1;
329 }
330
331 if ((size = PySequence_Fast_GET_SIZE(value_fast)) != array_dim) {
332 PyErr_Format(PyExc_ValueError,
333 "%.200s: sequence size is %d, expected %d",
334 error_prefix,
335 size,
336 array_dim);
337 Py_DECREF(value_fast);
338 return -1;
339 }
340
341 value_fast_items = PySequence_Fast_ITEMS(value_fast);
342 i = size;
343 while (i > 0) {
344 i--;
345 if (((array[i] = PyC_Long_AsI32((item = value_fast_items[i]))) == -1) && PyErr_Occurred()) {
346 PyErr_Format(PyExc_TypeError, "%.200s: sequence index %d expected an int", error_prefix, i);
347 size = -1;
348 break;
349 }
350 }
351 Py_DECREF(value_fast);
352
353 return size;
354 }
355
356 /* Parse sequence of array_dim sequences of integers and return allocated result. */
mathutils_array_parse_alloc_vi(int ** array,int array_dim,PyObject * value,const char * error_prefix)357 int mathutils_array_parse_alloc_vi(int **array,
358 int array_dim,
359 PyObject *value,
360 const char *error_prefix)
361 {
362 PyObject *value_fast;
363 int i, size;
364
365 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
366 /* PySequence_Fast sets the error */
367 return -1;
368 }
369
370 size = PySequence_Fast_GET_SIZE(value_fast);
371
372 if (size != 0) {
373 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
374 int *ip;
375
376 ip = *array = PyMem_Malloc(size * array_dim * sizeof(int));
377
378 for (i = 0; i < size; i++, ip += array_dim) {
379 PyObject *item = value_fast_items[i];
380
381 if (mathutils_int_array_parse(ip, array_dim, item, error_prefix) == -1) {
382 PyMem_Free(*array);
383 *array = NULL;
384 size = -1;
385 break;
386 }
387 }
388 }
389
390 Py_DECREF(value_fast);
391 return size;
392 }
393
394 /* Parse sequence of variable-length sequences of int and return allocated
395 * triple of arrays to represent the result:
396 * The flattened sequences are put into *array.
397 * The start index of each sequence goes into start_table.
398 * The length of each index goes into len_table.
399 */
mathutils_array_parse_alloc_viseq(int ** array,int ** start_table,int ** len_table,PyObject * value,const char * error_prefix)400 int mathutils_array_parse_alloc_viseq(
401 int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix)
402 {
403 PyObject *value_fast, *subseq;
404 int i, size, start, subseq_len;
405 int *ip;
406
407 *array = NULL;
408 *start_table = NULL;
409 *len_table = NULL;
410 if (!(value_fast = PySequence_Fast(value, error_prefix))) {
411 /* PySequence_Fast sets the error */
412 return -1;
413 }
414
415 size = PySequence_Fast_GET_SIZE(value_fast);
416
417 if (size != 0) {
418 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
419
420 *start_table = PyMem_Malloc(size * sizeof(int));
421 *len_table = PyMem_Malloc(size * sizeof(int));
422
423 /* First pass to set starts and len, and calculate size of array needed */
424 start = 0;
425 for (i = 0; i < size; i++) {
426 subseq = value_fast_items[i];
427 if ((subseq_len = (int)PySequence_Size(subseq)) == -1) {
428 PyErr_Format(
429 PyExc_ValueError, "%.200s: sequence expected to have subsequences", error_prefix);
430 PyMem_Free(*start_table);
431 PyMem_Free(*len_table);
432 Py_DECREF(value_fast);
433 *start_table = NULL;
434 *len_table = NULL;
435 return -1;
436 }
437 (*start_table)[i] = start;
438 (*len_table)[i] = subseq_len;
439 start += subseq_len;
440 }
441
442 ip = *array = PyMem_Malloc(start * sizeof(int));
443
444 /* Second pass to parse the subsequences into array */
445 for (i = 0; i < size; i++) {
446 subseq = value_fast_items[i];
447 subseq_len = (*len_table)[i];
448
449 if (mathutils_int_array_parse(ip, subseq_len, subseq, error_prefix) == -1) {
450 PyMem_Free(*array);
451 PyMem_Free(*start_table);
452 PyMem_Free(*len_table);
453 *array = NULL;
454 *len_table = NULL;
455 *start_table = NULL;
456 size = -1;
457 break;
458 }
459 ip += subseq_len;
460 }
461 }
462
463 Py_DECREF(value_fast);
464 return size;
465 }
466
mathutils_any_to_rotmat(float rmat[3][3],PyObject * value,const char * error_prefix)467 int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
468 {
469 if (EulerObject_Check(value)) {
470 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
471 return -1;
472 }
473
474 eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
475 return 0;
476 }
477 if (QuaternionObject_Check(value)) {
478 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
479 return -1;
480 }
481
482 float tquat[4];
483 normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
484 quat_to_mat3(rmat, tquat);
485 return 0;
486 }
487 if (MatrixObject_Check(value)) {
488 if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
489 return -1;
490 }
491 if (((MatrixObject *)value)->num_row < 3 || ((MatrixObject *)value)->num_col < 3) {
492 PyErr_Format(
493 PyExc_ValueError, "%.200s: matrix must have minimum 3x3 dimensions", error_prefix);
494 return -1;
495 }
496
497 matrix_as_3x3(rmat, (MatrixObject *)value);
498 normalize_m3(rmat);
499 return 0;
500 }
501
502 PyErr_Format(PyExc_TypeError,
503 "%.200s: expected a Euler, Quaternion or Matrix type, "
504 "found %.200s",
505 error_prefix,
506 Py_TYPE(value)->tp_name);
507 return -1;
508 }
509
510 /* ----------------------------------MATRIX FUNCTIONS-------------------- */
511
512 /* Utility functions */
513
514 /* LomontRRDCompare4, Ever Faster Float Comparisons by Randy Dillon */
515 /* XXX We may want to use 'safer' BLI's compare_ff_relative ultimately?
516 * LomontRRDCompare4() is an optimized version of Dawson's AlmostEqual2sComplement()
517 * (see [1] and [2]).
518 * Dawson himself now claims this is not a 'safe' thing to do
519 * (pushing ULP method beyond its limits),
520 * an recommends using work from [3] instead, which is done in BLI func...
521 *
522 * [1] http://www.randydillon.org/Papers/2007/everfast.htm
523 * [2] http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
524 * [3] https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
525 * instead.
526 */
527 #define SIGNMASK(i) (-(int)(((uint)(i)) >> 31))
528
EXPP_FloatsAreEqual(float af,float bf,int maxDiff)529 int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
530 {
531 /* solid, fast routine across all platforms
532 * with constant time behavior */
533 const int ai = *(int *)(&af);
534 const int bi = *(int *)(&bf);
535 const int test = SIGNMASK(ai ^ bi);
536 int diff, v1, v2;
537
538 BLI_assert((0 == test) || (0xFFFFFFFF == test));
539 diff = (ai ^ (test & 0x7fffffff)) - bi;
540 v1 = maxDiff + diff;
541 v2 = maxDiff - diff;
542 return (v1 | v2) >= 0;
543 }
544
545 /*---------------------- EXPP_VectorsAreEqual -------------------------
546 * Builds on EXPP_FloatsAreEqual to test vectors */
EXPP_VectorsAreEqual(const float * vecA,const float * vecB,int size,int floatSteps)547 int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
548 {
549 int x;
550 for (x = 0; x < size; x++) {
551 if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0) {
552 return 0;
553 }
554 }
555 return 1;
556 }
557
558 #ifndef MATH_STANDALONE
559 /* dynstr as python string utility functions, frees 'ds'! */
mathutils_dynstr_to_py(struct DynStr * ds)560 PyObject *mathutils_dynstr_to_py(struct DynStr *ds)
561 {
562 const int ds_len = BLI_dynstr_get_len(ds); /* space for \0 */
563 char *ds_buf = PyMem_Malloc(ds_len + 1);
564 PyObject *ret;
565 BLI_dynstr_get_cstring_ex(ds, ds_buf);
566 BLI_dynstr_free(ds);
567 ret = PyUnicode_FromStringAndSize(ds_buf, ds_len);
568 PyMem_Free(ds_buf);
569 return ret;
570 }
571 #endif
572
573 /* Mathutils Callbacks */
574
575 /* For mathutils internal use only,
576 * eventually should re-alloc but to start with we only have a few users. */
577 #define MATHUTILS_TOT_CB 17
578 static Mathutils_Callback *mathutils_callbacks[MATHUTILS_TOT_CB] = {NULL};
579
Mathutils_RegisterCallback(Mathutils_Callback * cb)580 uchar Mathutils_RegisterCallback(Mathutils_Callback *cb)
581 {
582 uchar i;
583
584 /* find the first free slot */
585 for (i = 0; mathutils_callbacks[i]; i++) {
586 if (mathutils_callbacks[i] == cb) {
587 /* already registered? */
588 return i;
589 }
590 }
591
592 BLI_assert(i + 1 < MATHUTILS_TOT_CB);
593
594 mathutils_callbacks[i] = cb;
595 return i;
596 }
597
598 /* use macros to check for NULL */
_BaseMathObject_ReadCallback(BaseMathObject * self)599 int _BaseMathObject_ReadCallback(BaseMathObject *self)
600 {
601 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
602 if (LIKELY(cb->get(self, self->cb_subtype) != -1)) {
603 return 0;
604 }
605
606 if (!PyErr_Occurred()) {
607 PyErr_Format(PyExc_RuntimeError, "%s read, user has become invalid", Py_TYPE(self)->tp_name);
608 }
609 return -1;
610 }
611
_BaseMathObject_WriteCallback(BaseMathObject * self)612 int _BaseMathObject_WriteCallback(BaseMathObject *self)
613 {
614 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
615 if (LIKELY(cb->set(self, self->cb_subtype) != -1)) {
616 return 0;
617 }
618
619 if (!PyErr_Occurred()) {
620 PyErr_Format(PyExc_RuntimeError, "%s write, user has become invalid", Py_TYPE(self)->tp_name);
621 }
622 return -1;
623 }
624
_BaseMathObject_ReadIndexCallback(BaseMathObject * self,int index)625 int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
626 {
627 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
628 if (LIKELY(cb->get_index(self, self->cb_subtype, index) != -1)) {
629 return 0;
630 }
631
632 if (!PyErr_Occurred()) {
633 PyErr_Format(
634 PyExc_RuntimeError, "%s read index, user has become invalid", Py_TYPE(self)->tp_name);
635 }
636 return -1;
637 }
638
_BaseMathObject_WriteIndexCallback(BaseMathObject * self,int index)639 int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
640 {
641 Mathutils_Callback *cb = mathutils_callbacks[self->cb_type];
642 if (LIKELY(cb->set_index(self, self->cb_subtype, index) != -1)) {
643 return 0;
644 }
645
646 if (!PyErr_Occurred()) {
647 PyErr_Format(
648 PyExc_RuntimeError, "%s write index, user has become invalid", Py_TYPE(self)->tp_name);
649 }
650 return -1;
651 }
652
_BaseMathObject_RaiseFrozenExc(const BaseMathObject * self)653 void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self)
654 {
655 PyErr_Format(PyExc_TypeError, "%s is frozen (immutable)", Py_TYPE(self)->tp_name);
656 }
657
_BaseMathObject_RaiseNotFrozenExc(const BaseMathObject * self)658 void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self)
659 {
660 PyErr_Format(
661 PyExc_TypeError, "%s is not frozen (mutable), call freeze first", Py_TYPE(self)->tp_name);
662 }
663
664 /* BaseMathObject generic functions for all mathutils types */
665 char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only).";
BaseMathObject_owner_get(BaseMathObject * self,void * UNUSED (closure))666 PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
667 {
668 PyObject *ret = self->cb_user ? self->cb_user : Py_None;
669 return Py_INCREF_RET(ret);
670 }
671
672 char BaseMathObject_is_wrapped_doc[] =
673 "True when this object wraps external data (read-only).\n\n:type: boolean";
BaseMathObject_is_wrapped_get(BaseMathObject * self,void * UNUSED (closure))674 PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure))
675 {
676 return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_WRAP) != 0);
677 }
678
679 char BaseMathObject_is_frozen_doc[] =
680 "True when this object has been frozen (read-only).\n\n:type: boolean";
BaseMathObject_is_frozen_get(BaseMathObject * self,void * UNUSED (closure))681 PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *UNUSED(closure))
682 {
683 return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_FROZEN) != 0);
684 }
685
686 char BaseMathObject_freeze_doc[] =
687 ".. function:: freeze()\n"
688 "\n"
689 " Make this object immutable.\n"
690 "\n"
691 " After this the object can be hashed, used in dictionaries & sets.\n"
692 "\n"
693 " :return: An instance of this object.\n";
BaseMathObject_freeze(BaseMathObject * self)694 PyObject *BaseMathObject_freeze(BaseMathObject *self)
695 {
696 if ((self->flag & BASE_MATH_FLAG_IS_WRAP) || (self->cb_user != NULL)) {
697 PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped/owned data");
698 return NULL;
699 }
700
701 self->flag |= BASE_MATH_FLAG_IS_FROZEN;
702
703 return Py_INCREF_RET((PyObject *)self);
704 }
705
BaseMathObject_traverse(BaseMathObject * self,visitproc visit,void * arg)706 int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
707 {
708 Py_VISIT(self->cb_user);
709 return 0;
710 }
711
BaseMathObject_clear(BaseMathObject * self)712 int BaseMathObject_clear(BaseMathObject *self)
713 {
714 Py_CLEAR(self->cb_user);
715 return 0;
716 }
717
BaseMathObject_dealloc(BaseMathObject * self)718 void BaseMathObject_dealloc(BaseMathObject *self)
719 {
720 /* only free non wrapped */
721 if ((self->flag & BASE_MATH_FLAG_IS_WRAP) == 0) {
722 PyMem_Free(self->data);
723 }
724
725 if (self->cb_user) {
726 PyObject_GC_UnTrack(self);
727 BaseMathObject_clear(self);
728 }
729
730 Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); /* breaks subtypes. */
731 }
732
733 /*----------------------------MODULE INIT-------------------------*/
734 static struct PyMethodDef M_Mathutils_methods[] = {
735 {NULL, NULL, 0, NULL},
736 };
737
738 static struct PyModuleDef M_Mathutils_module_def = {
739 PyModuleDef_HEAD_INIT,
740 "mathutils", /* m_name */
741 M_Mathutils_doc, /* m_doc */
742 0, /* m_size */
743 M_Mathutils_methods, /* m_methods */
744 NULL, /* m_reload */
745 NULL, /* m_traverse */
746 NULL, /* m_clear */
747 NULL, /* m_free */
748 };
749
750 /* submodules only */
751 #include "mathutils_geometry.h"
752 #include "mathutils_interpolate.h"
753 #ifndef MATH_STANDALONE
754 # include "mathutils_bvhtree.h"
755 # include "mathutils_kdtree.h"
756 # include "mathutils_noise.h"
757 #endif
758
PyInit_mathutils(void)759 PyMODINIT_FUNC PyInit_mathutils(void)
760 {
761 PyObject *mod;
762 PyObject *submodule;
763 PyObject *sys_modules = PyImport_GetModuleDict();
764
765 if (PyType_Ready(&vector_Type) < 0) {
766 return NULL;
767 }
768 if (PyType_Ready(&matrix_Type) < 0) {
769 return NULL;
770 }
771 if (PyType_Ready(&matrix_access_Type) < 0) {
772 return NULL;
773 }
774 if (PyType_Ready(&euler_Type) < 0) {
775 return NULL;
776 }
777 if (PyType_Ready(&quaternion_Type) < 0) {
778 return NULL;
779 }
780 if (PyType_Ready(&color_Type) < 0) {
781 return NULL;
782 }
783
784 mod = PyModule_Create(&M_Mathutils_module_def);
785
786 /* each type has its own new() function */
787 PyModule_AddObject(mod, vector_Type.tp_name, (PyObject *)&vector_Type);
788 PyModule_AddObject(mod, matrix_Type.tp_name, (PyObject *)&matrix_Type);
789 PyModule_AddObject(mod, euler_Type.tp_name, (PyObject *)&euler_Type);
790 PyModule_AddObject(mod, quaternion_Type.tp_name, (PyObject *)&quaternion_Type);
791 PyModule_AddObject(mod, color_Type.tp_name, (PyObject *)&color_Type);
792
793 /* submodule */
794 PyModule_AddObject(mod, "geometry", (submodule = PyInit_mathutils_geometry()));
795 /* XXX, python doesn't do imports with this usefully yet
796 * 'from mathutils.geometry import PolyFill'
797 * ...fails without this. */
798 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
799
800 PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate()));
801 /* XXX, python doesn't do imports with this usefully yet
802 * 'from mathutils.geometry import PolyFill'
803 * ...fails without this. */
804 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
805
806 #ifndef MATH_STANDALONE
807 /* Noise submodule */
808 PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
809 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
810
811 /* BVHTree submodule */
812 PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree()));
813 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
814
815 /* KDTree_3d submodule */
816 PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree()));
817 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
818 #endif
819
820 mathutils_matrix_row_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_row_cb);
821 mathutils_matrix_col_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_col_cb);
822 mathutils_matrix_translation_cb_index = Mathutils_RegisterCallback(
823 &mathutils_matrix_translation_cb);
824
825 return mod;
826 }
827