Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/python/mathutils')
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt2
-rw-r--r--source/blender/python/mathutils/mathutils.c132
-rw-r--r--source/blender/python/mathutils/mathutils.h53
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c140
-rw-r--r--source/blender/python/mathutils/mathutils_Color.h15
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c143
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.h15
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c281
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h21
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c224
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.h15
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c235
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h22
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c816
-rw-r--r--source/blender/python/mathutils/mathutils_interpolate.c137
-rw-r--r--source/blender/python/mathutils/mathutils_interpolate.h32
-rw-r--r--source/blender/python/mathutils/mathutils_kdtree.c14
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c14
18 files changed, 1408 insertions, 903 deletions
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index 133b8d3895c..ef6b090140b 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SRC
mathutils_Quaternion.c
mathutils_Vector.c
mathutils_geometry.c
+ mathutils_interpolate.c
mathutils_kdtree.c
mathutils_noise.c
@@ -48,6 +49,7 @@ set(SRC
mathutils_Quaternion.h
mathutils_Vector.h
mathutils_geometry.h
+ mathutils_interpolate.h
mathutils_kdtree.h
mathutils_noise.h
)
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 349f8483fb0..7b51b08451b 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -31,12 +31,25 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/python_utildefines.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
PyDoc_STRVAR(M_Mathutils_doc,
-"This module provides access to matrices, eulers, quaternions and vectors."
+"This module provides access to the math classes:\n"
+"\n"
+"- :class:`Color`,\n"
+"- :class:`Euler`,\n"
+"- :class:`Matrix`,\n"
+"- :class:`Quaternion`,\n"
+"- :class:`Vector`,\n"
+"\n"
+".. note::\n"
+"\n"
+" Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
+" such as tuples, lists."
);
static int mathutils_array_parse_fast(float *array,
int size,
@@ -66,11 +79,45 @@ static int mathutils_array_parse_fast(float *array,
return size;
}
+/**
+ * helper function that returns a Python ``__hash__``.
+ *
+ * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
+ */
+Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
+{
+ int i;
+ Py_uhash_t x; /* Unsigned for defined overflow behavior. */
+ Py_hash_t y;
+ Py_uhash_t mult;
+ Py_ssize_t len;
+
+ mult = _PyHASH_MULTIPLIER;
+ len = array_len;
+ x = 0x345678UL;
+ i = 0;
+ while (--len >= 0) {
+ y = _Py_HashDouble((double)(array[i++]));
+ if (y == -1)
+ return -1;
+ x = (x ^ y) * mult;
+ /* the cast might truncate len; that doesn't change hash stability */
+ mult += (Py_hash_t)(82520UL + len + len);
+ }
+ x += 97531UL;
+ if (x == (Py_uhash_t)-1)
+ x = -2;
+ return x;
+}
+
/* helper functionm returns length of the 'value', -1 on error */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
+ const int flag = array_max;
int size;
+ array_max &= ~MU_ARRAY_FLAGS;
+
#if 1 /* approx 6x speedup for mathutils types */
if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
@@ -82,6 +129,10 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
return -1;
}
+ if (flag & MU_ARRAY_SPILL) {
+ CLAMP_MAX(size, array_max);
+ }
+
if (size > array_max || size < array_min) {
if (array_max == array_min) {
PyErr_Format(PyExc_ValueError,
@@ -97,7 +148,6 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
}
memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
- return size;
}
else
#endif
@@ -112,6 +162,10 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
size = PySequence_Fast_GET_SIZE(value_fast);
+ if (flag & MU_ARRAY_SPILL) {
+ CLAMP_MAX(size, array_max);
+ }
+
if (size > array_max || size < array_min) {
if (array_max == array_min) {
PyErr_Format(PyExc_ValueError,
@@ -127,8 +181,19 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
return -1;
}
- return mathutils_array_parse_fast(array, size, value_fast, error_prefix);
+ size = mathutils_array_parse_fast(array, size, value_fast, error_prefix);
}
+
+ if (size != -1) {
+ if (flag & MU_ARRAY_ZERO) {
+ int size_left = array_max - size;
+ if (size_left) {
+ memset(&array[size], 0, sizeof(float) * size_left);
+ }
+ }
+ }
+
+ return size;
}
/* on error, -1 is returned and no allocation is made */
@@ -196,6 +261,7 @@ int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, c
int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix)
{
PyObject *value_fast = NULL;
+ const int array_dim_flag = array_dim;
int i, size;
/* non list/tuple cases */
@@ -209,12 +275,14 @@ int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value,
if (size != 0) {
float *fp;
+ array_dim &= ~MU_ARRAY_FLAGS;
+
fp = *array = PyMem_Malloc(size * array_dim * sizeof(float));
for (i = 0; i < size; i++, fp += array_dim) {
PyObject *item = PySequence_Fast_GET_ITEM(value, i);
- if (mathutils_array_parse(fp, array_dim, array_dim, item, error_prefix) == -1) {
+ if (mathutils_array_parse(fp, array_dim, array_dim_flag, item, error_prefix) == -1) {
PyMem_Free(*array);
*array = NULL;
size = -1;
@@ -415,19 +483,59 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
return -1;
}
+void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self)
+{
+ PyErr_Format(PyExc_TypeError,
+ "%s is frozen (immutable)",
+ Py_TYPE(self)->tp_name);
+}
+
+void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self)
+{
+ PyErr_Format(PyExc_TypeError,
+ "%s is not frozen (mutable), call freeze first",
+ Py_TYPE(self)->tp_name);
+}
+
/* BaseMathObject generic functions for all mathutils types */
char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only).";
PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
{
PyObject *ret = self->cb_user ? self->cb_user : Py_None;
- Py_INCREF(ret);
- return ret;
+ return Py_INCREF_RET(ret);
}
char BaseMathObject_is_wrapped_doc[] = "True when this object wraps external data (read-only).\n\n:type: boolean";
PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure))
{
- return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1 : 0);
+ return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_WRAP) != 0);
+}
+
+char BaseMathObject_is_frozen_doc[] = "True when this object has been frozen (read-only).\n\n:type: boolean";
+PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *UNUSED(closure))
+{
+ return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_FROZEN) != 0);
+}
+
+char BaseMathObject_freeze_doc[] =
+".. function:: freeze()\n"
+"\n"
+" Make this object immutable.\n"
+"\n"
+" After this the object can be hashed, used in dictionaries & sets.\n"
+"\n"
+" :return: An instance of this object.\n"
+;
+PyObject *BaseMathObject_freeze(BaseMathObject *self)
+{
+ if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
+ PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data");
+ return NULL;
+ }
+
+ self->flag |= BASE_MATH_FLAG_IS_FROZEN;
+
+ return Py_INCREF_RET((PyObject *)self);;
}
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
@@ -445,7 +553,7 @@ int BaseMathObject_clear(BaseMathObject *self)
void BaseMathObject_dealloc(BaseMathObject *self)
{
/* only free non wrapped */
- if (self->wrapped != Py_WRAP) {
+ if ((self->flag & BASE_MATH_FLAG_IS_WRAP) == 0) {
PyMem_Free(self->data);
}
@@ -477,6 +585,7 @@ static struct PyModuleDef M_Mathutils_module_def = {
/* submodules only */
#include "mathutils_geometry.h"
+#include "mathutils_interpolate.h"
#ifndef MATH_STANDALONE
# include "mathutils_kdtree.h"
# include "mathutils_noise.h"
@@ -518,6 +627,13 @@ PyMODINIT_FUNC PyInit_mathutils(void)
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
Py_INCREF(submodule);
+ PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate()));
+ /* XXX, python doesnt do imports with this usefully yet
+ * 'from mathutils.geometry import PolyFill'
+ * ...fails without this. */
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
#ifndef MATH_STANDALONE
/* Noise submodule */
PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index eb25d9bff07..e653b45389b 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -29,11 +29,25 @@
/* Can cast different mathutils types to this, use for generic funcs */
+#include "BLI_compiler_attrs.h"
+
struct DynStr;
extern char BaseMathObject_is_wrapped_doc[];
+extern char BaseMathObject_is_frozen_doc[];
extern char BaseMathObject_owner_doc[];
+#define BASE_MATH_NEW(struct_name, root_type, base_type) \
+ (struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : _PyObject_GC_New(&(root_type))));
+
+
+/* BaseMathObject.flag */
+enum {
+ BASE_MATH_FLAG_IS_WRAP = (1 << 0),
+ BASE_MATH_FLAG_IS_FROZEN = (1 << 1),
+};
+#define BASE_MATH_FLAG_DEFAULT 0
+
#define BASE_MATH_MEMBERS(_data) \
PyObject_VAR_HEAD \
float *_data; /* array of data (alias), wrapped status depends on wrapped status */ \
@@ -42,7 +56,7 @@ extern char BaseMathObject_owner_doc[];
unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ \
unsigned char cb_subtype; /* subtype: location, rotation... \
* to avoid defining many new functions for every attribute of the same type */ \
- unsigned char wrapped /* wrapped data type? */ \
+ unsigned char flag /* wrapped data type? */ \
typedef struct {
BASE_MATH_MEMBERS(data);
@@ -57,6 +71,10 @@ typedef struct {
PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *);
PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *);
+PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *);
+
+extern char BaseMathObject_freeze_doc[];
+PyObject *BaseMathObject_freeze(BaseMathObject *self);
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg);
int BaseMathObject_clear(BaseMathObject *self);
@@ -67,9 +85,6 @@ PyMODINIT_FUNC PyInit_mathutils(void);
int EXPP_FloatsAreEqual(float A, float B, int floatSteps);
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps);
-#define Py_NEW 1
-#define Py_WRAP 2
-
typedef struct Mathutils_Callback Mathutils_Callback;
typedef int (*BaseMathCheckFunc)(BaseMathObject *); /* checks the user is still valid */
@@ -93,6 +108,9 @@ int _BaseMathObject_WriteCallback(BaseMathObject *self);
int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index);
int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
+void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self);
+void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self);
+
/* since this is called so often avoid where possible */
#define BaseMath_ReadCallback(_self) \
(((_self)->cb_user ? _BaseMathObject_ReadCallback((BaseMathObject *)_self):0))
@@ -103,12 +121,39 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
#define BaseMath_WriteIndexCallback(_self, _index) \
(((_self)->cb_user ? _BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):0))
+/* support BASE_MATH_FLAG_IS_FROZEN */
+#define BaseMath_ReadCallback_ForWrite(_self) \
+ (UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \
+ (_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : (BaseMath_ReadCallback(_self)))
+
+#define BaseMath_ReadIndexCallback_ForWrite(_self, _index) \
+ (UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \
+ (_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : (BaseMath_ReadIndexCallback(_self, _index)))
+
+#define BaseMath_Prepare_ForWrite(_self) \
+ (UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \
+ (_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : 0)
+
+#define BaseMathObject_Prepare_ForHash(_self) \
+ (UNLIKELY(((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) == 0) ? \
+ (_BaseMathObject_RaiseNotFrozenExc((BaseMathObject *)_self), -1) : 0)
+
/* utility func */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix);
int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
+Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
+
+/* zero remaining unused elements of the array */
+#define MU_ARRAY_ZERO (1 << 30)
+/* ignore larger py sequences than requested (just use first elements),
+ * handy when using 3d vectors as 2d */
+#define MU_ARRAY_SPILL (1 << 31)
+
+#define MU_ARRAY_FLAGS (MU_ARRAY_ZERO | MU_ARRAY_SPILL)
+
int column_vector_multiplication(float rvec[4], VectorObject *vec, MatrixObject *mat);
#ifndef MATH_STANDALONE
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index aee2b9e9711..add8c2451ff 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -32,6 +32,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/python_utildefines.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
@@ -64,7 +66,7 @@ static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
"more than a single arg given");
return NULL;
}
- return Color_CreatePyObject(col, Py_NEW, type);
+ return Color_CreatePyObject(col, type);
}
/* -----------------------------METHODS---------------------------- */
@@ -107,7 +109,7 @@ static PyObject *Color_copy(ColorObject *self)
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- return Color_CreatePyObject(self->col, Py_NEW, Py_TYPE(self));
+ return Color_CreatePyObject(self->col, Py_TYPE(self));
}
static PyObject *Color_deepcopy(ColorObject *self, PyObject *args)
{
@@ -187,7 +189,18 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
return NULL;
}
- return Py_INCREF(res), res;
+ return Py_INCREF_RET(res);
+}
+
+static Py_hash_t Color_hash(ColorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1)
+ return -1;
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1)
+ return -1;
+
+ return mathutils_array_hash(self->col, COLOR_SIZE);
}
/* ---------------------SEQUENCE PROTOCOLS------------------------ */
@@ -220,8 +233,12 @@ static PyObject *Color_item(ColorObject *self, int i)
/* sequence accessor (set) */
static int Color_ass_item(ColorObject *self, int i, PyObject *value)
{
- float f = PyFloat_AsDouble(value);
+ float f;
+
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return -1;
+ f = PyFloat_AsDouble(value);
if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */
PyErr_SetString(PyExc_TypeError,
"color[item] = x: "
@@ -273,7 +290,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
int i, size;
float col[COLOR_SIZE];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
CLAMP(begin, 0, COLOR_SIZE);
@@ -411,7 +428,7 @@ static PyObject *Color_add(PyObject *v1, PyObject *v2)
add_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE);
- return Color_CreatePyObject(col, Py_NEW, Py_TYPE(v1));
+ return Color_CreatePyObject(col, Py_TYPE(v1));
}
/* addition in-place: obj += obj */
@@ -429,7 +446,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
color1 = (ColorObject *)v1;
color2 = (ColorObject *)v2;
- if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
+ if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
return NULL;
add_vn_vn(color1->col, color2->col, COLOR_SIZE);
@@ -460,7 +477,7 @@ static PyObject *Color_sub(PyObject *v1, PyObject *v2)
sub_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE);
- return Color_CreatePyObject(col, Py_NEW, Py_TYPE(v1));
+ return Color_CreatePyObject(col, Py_TYPE(v1));
}
/* subtraction in-place: obj -= obj */
@@ -478,7 +495,7 @@ static PyObject *Color_isub(PyObject *v1, PyObject *v2)
color1 = (ColorObject *)v1;
color2 = (ColorObject *)v2;
- if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
+ if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
return NULL;
sub_vn_vn(color1->col, color2->col, COLOR_SIZE);
@@ -492,7 +509,7 @@ static PyObject *color_mul_float(ColorObject *color, const float scalar)
{
float tcol[COLOR_SIZE];
mul_vn_vn_fl(tcol, color->col, COLOR_SIZE, scalar);
- return Color_CreatePyObject(tcol, Py_NEW, Py_TYPE(color));
+ return Color_CreatePyObject(tcol, Py_TYPE(color));
}
@@ -577,7 +594,7 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2)
ColorObject *color = (ColorObject *)v1;
float scalar;
- if (BaseMath_ReadCallback(color) == -1)
+ if (BaseMath_ReadCallback_ForWrite(color) == -1)
return NULL;
/* only support color *= float */
@@ -603,7 +620,7 @@ static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
ColorObject *color = (ColorObject *)v1;
float scalar;
- if (BaseMath_ReadCallback(color) == -1)
+ if (BaseMath_ReadCallback_ForWrite(color) == -1)
return NULL;
/* only support color /= float */
@@ -639,7 +656,7 @@ static PyObject *Color_neg(ColorObject *self)
return NULL;
negate_vn_vn(tcol, self->col, COLOR_SIZE);
- return Color_CreatePyObject(tcol, Py_NEW, Py_TYPE(self));
+ return Color_CreatePyObject(tcol, Py_TYPE(self));
}
@@ -726,7 +743,7 @@ static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
return -1;
}
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
rgb_to_hsv_v(self->col, hsv);
@@ -753,9 +770,10 @@ static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
ret = PyTuple_New(3);
- PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(hsv[0]));
- PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(hsv[1]));
- PyTuple_SET_ITEM(ret, 2, PyFloat_FromDouble(hsv[2]));
+ PyTuple_SET_ITEMS(ret,
+ PyFloat_FromDouble(hsv[0]),
+ PyFloat_FromDouble(hsv[1]),
+ PyFloat_FromDouble(hsv[2]));
return ret;
}
@@ -766,6 +784,9 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur
if (mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1)
return -1;
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return -1;
+
CLAMP(hsv[0], 0.0f, 1.0f);
CLAMP(hsv[1], 0.0f, 1.0f);
CLAMP(hsv[2], 0.0f, 1.0f);
@@ -793,6 +814,7 @@ static PyGetSetDef Color_getseters[] = {
{(char *)"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, (char *)Color_hsv_doc, (void *)0},
{(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
+ {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -803,12 +825,20 @@ static struct PyMethodDef Color_methods[] = {
{"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
{"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
{"__deepcopy__", (PyCFunction) Color_deepcopy, METH_VARARGS, Color_copy_doc},
+
+ /* base-math methods */
+ {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
{NULL, NULL, 0, NULL}
};
/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(color_doc,
-"This object gives access to Colors in Blender."
+".. class:: Color(rgb)\n"
+"\n"
+" This object gives access to Colors in Blender.\n"
+"\n"
+" :param rgb: (r, g, b) color values\n"
+" :type rgb: 3d vector\n"
);
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -824,7 +854,7 @@ PyTypeObject color_Type = {
&Color_NumMethods, /* tp_as_number */
&Color_SeqMethods, /* tp_as_sequence */
&Color_AsMapping, /* tp_as_mapping */
- NULL, /* tp_hash */
+ (hashfunc)Color_hash, /* tp_hash */
NULL, /* tp_call */
#ifndef MATH_STANDALONE
(reprfunc) Color_str, /* tp_str */
@@ -862,40 +892,60 @@ PyTypeObject color_Type = {
NULL, /* tp_weaklist */
NULL /* tp_del */
};
-/* ------------------------Color_CreatePyObject (internal)------------- */
-/* creates a new color object */
-/* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- * (i.e. it was allocated elsewhere by MEM_mallocN())
- * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- * (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type)
+
+PyObject *Color_CreatePyObject(
+ const float col[3],
+ PyTypeObject *base_type)
{
ColorObject *self;
+ float *col_alloc;
- self = base_type ? (ColorObject *)base_type->tp_alloc(base_type, 0) :
- (ColorObject *)PyObject_GC_New(ColorObject, &color_Type);
+ col_alloc = PyMem_Malloc(COLOR_SIZE * sizeof(float));
+ if (UNLIKELY(col_alloc == NULL)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Color(): "
+ "problem allocating data");
+ return NULL;
+ }
+ self = BASE_MATH_NEW(ColorObject, color_Type, base_type);
if (self) {
+ self->col = col_alloc;
+
/* init callbacks as NULL */
self->cb_user = NULL;
self->cb_type = self->cb_subtype = 0;
- if (type == Py_WRAP) {
- self->col = col;
- self->wrapped = Py_WRAP;
- }
- else if (type == Py_NEW) {
- self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float));
- if (col)
- copy_v3_v3(self->col, col);
- else
- zero_v3(self->col);
-
- self->wrapped = Py_NEW;
- }
- else {
- Py_FatalError("Color(): invalid type!");
- }
+ /* NEW */
+ if (col)
+ copy_v3_v3(self->col, col);
+ else
+ zero_v3(self->col);
+
+ self->flag = BASE_MATH_FLAG_DEFAULT;
+ }
+ else {
+ PyMem_Free(col_alloc);
+ }
+
+ return (PyObject *)self;
+}
+
+PyObject *Color_CreatePyObject_wrap(
+ float col[3],
+ PyTypeObject *base_type)
+{
+ ColorObject *self;
+
+ self = BASE_MATH_NEW(ColorObject, color_Type, base_type);
+ if (self) {
+ /* init callbacks as NULL */
+ self->cb_user = NULL;
+ self->cb_type = self->cb_subtype = 0;
+
+ /* WRAP */
+ self->col = col;
+ self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
}
return (PyObject *)self;
@@ -904,7 +954,7 @@ PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type)
PyObject *Color_CreatePyObject_cb(PyObject *cb_user,
unsigned char cb_type, unsigned char cb_subtype)
{
- ColorObject *self = (ColorObject *)Color_CreatePyObject(NULL, Py_NEW, NULL);
+ ColorObject *self = (ColorObject *)Color_CreatePyObject(NULL, NULL);
if (self) {
Py_INCREF(cb_user);
self->cb_user = cb_user;
diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h
index 193d30a2b6f..1290f73da62 100644
--- a/source/blender/python/mathutils/mathutils_Color.h
+++ b/source/blender/python/mathutils/mathutils_Color.h
@@ -42,8 +42,17 @@ typedef struct {
* blender (stored in blend_data). This is an either/or struct not both*/
/* prototypes */
-PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type);
-PyObject *Color_CreatePyObject_cb(PyObject *cb_user,
- unsigned char cb_type, unsigned char cb_subtype);
+PyObject *Color_CreatePyObject(
+ const float col[3],
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT;
+PyObject *Color_CreatePyObject_wrap(
+ float col[3],
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+PyObject *Color_CreatePyObject_cb(
+ PyObject *cb_user,
+ unsigned char cb_type, unsigned char cb_subtype
+ ) ATTR_WARN_UNUSED_RESULT;
#endif /* __MATHUTILS_COLOR_H__ */
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index f6d124938a4..54adc826af7 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -31,6 +31,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/python_utildefines.h"
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
@@ -70,7 +71,7 @@ static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
break;
}
- return Euler_CreatePyObject(eul, order, Py_NEW, type);
+ return Euler_CreatePyObject(eul, order, type);
}
/* internal use, assume read callback is done */
@@ -150,7 +151,7 @@ static PyObject *Euler_to_quaternion(EulerObject *self)
eulO_to_quat(quat, self->eul, self->order);
- return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
+ return Quaternion_CreatePyObject(quat, NULL);
}
/* return a matrix representation of the euler */
@@ -171,7 +172,7 @@ static PyObject *Euler_to_matrix(EulerObject *self)
eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
- return Matrix_CreatePyObject(mat, 3, 3, Py_NEW, NULL);
+ return Matrix_CreatePyObject(mat, 3, 3, NULL);
}
PyDoc_STRVAR(Euler_zero_doc,
@@ -181,6 +182,9 @@ PyDoc_STRVAR(Euler_zero_doc,
);
static PyObject *Euler_zero(EulerObject *self)
{
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return NULL;
+
zero_v3(self->eul);
if (BaseMath_WriteCallback(self) == -1)
@@ -219,7 +223,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
return NULL;
}
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
@@ -233,7 +237,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
PyDoc_STRVAR(Euler_rotate_doc,
".. method:: rotate(other)\n"
"\n"
-" Rotates the euler a by another mathutils value.\n"
+" Rotates the euler by another mathutils value.\n"
"\n"
" :arg other: rotation component of mathutils value\n"
" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
@@ -242,7 +246,7 @@ static PyObject *Euler_rotate(EulerObject *self, PyObject *value)
{
float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1)
@@ -269,7 +273,7 @@ static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
{
float teul[EULER_SIZE];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value,
@@ -304,7 +308,7 @@ static PyObject *Euler_copy(EulerObject *self)
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- return Euler_CreatePyObject(self->eul, self->order, Py_NEW, Py_TYPE(self));
+ return Euler_CreatePyObject(self->eul, self->order, Py_TYPE(self));
}
static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
{
@@ -382,7 +386,18 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
return NULL;
}
- return Py_INCREF(res), res;
+ return Py_INCREF_RET(res);
+}
+
+static Py_hash_t Euler_hash(EulerObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1)
+ return -1;
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1)
+ return -1;
+
+ return mathutils_array_hash(self->eul, EULER_SIZE);
}
/* ---------------------SEQUENCE PROTOCOLS------------------------ */
@@ -415,8 +430,12 @@ static PyObject *Euler_item(EulerObject *self, int i)
/* sequence accessor (set) */
static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
{
- float f = PyFloat_AsDouble(value);
+ float f;
+
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return -1;
+ f = PyFloat_AsDouble(value);
if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */
PyErr_SetString(PyExc_TypeError,
"euler[attribute] = x: "
@@ -469,7 +488,7 @@ static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
int i, size;
float eul[EULER_SIZE];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
CLAMP(begin, 0, EULER_SIZE);
@@ -614,12 +633,18 @@ static PyObject *Euler_order_get(EulerObject *self, void *UNUSED(closure))
static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(closure))
{
- const char *order_str = _PyUnicode_AsString(value);
- short order = euler_order_from_string(order_str, "euler.order");
+ const char *order_str;
+ short order;
- if (order == -1)
+ if (BaseMath_Prepare_ForWrite(self) == -1)
return -1;
+ if (((order_str = _PyUnicode_AsString(value)) == NULL) ||
+ ((order = euler_order_from_string(order_str, "euler.order")) == -1))
+ {
+ return -1;
+ }
+
self->order = order;
(void)BaseMath_WriteCallback(self); /* order can be written back */
return 0;
@@ -635,6 +660,7 @@ static PyGetSetDef Euler_getseters[] = {
{(char *)"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, (void *)NULL},
{(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
+ {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -651,12 +677,22 @@ static struct PyMethodDef Euler_methods[] = {
{"copy", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
{"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
{"__deepcopy__", (PyCFunction) Euler_deepcopy, METH_VARARGS, Euler_copy_doc},
+
+ /* base-math methods */
+ {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
{NULL, NULL, 0, NULL}
};
/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(euler_doc,
-"This object gives access to Eulers in Blender."
+".. class:: Euler(angles, order='XYZ')\n"
+"\n"
+" This object gives access to Eulers in Blender.\n"
+"\n"
+" :param angles: Three angles, in radians.\n"
+" :type angles: 3d vector\n"
+" :param order: Optional order of the angles, a permutation of ``XYZ``.\n"
+" :type order: str\n"
);
PyTypeObject euler_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -672,7 +708,7 @@ PyTypeObject euler_Type = {
NULL, /* tp_as_number */
&Euler_SeqMethods, /* tp_as_sequence */
&Euler_AsMapping, /* tp_as_mapping */
- NULL, /* tp_hash */
+ (hashfunc)Euler_hash, /* tp_hash */
NULL, /* tp_call */
#ifndef MATH_STANDALONE
(reprfunc) Euler_str, /* tp_str */
@@ -710,53 +746,74 @@ PyTypeObject euler_Type = {
NULL, /* tp_weaklist */
NULL /* tp_del */
};
-/* ------------------------Euler_CreatePyObject (internal)------------- */
-/* creates a new euler object */
-/* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- * (i.e. it was allocated elsewhere by MEM_mallocN())
- * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- * (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *Euler_CreatePyObject(float eul[3], const short order, int type, PyTypeObject *base_type)
+
+
+PyObject *Euler_CreatePyObject(
+ const float eul[3], const short order,
+ PyTypeObject *base_type)
{
EulerObject *self;
+ float *eul_alloc;
- self = base_type ? (EulerObject *)base_type->tp_alloc(base_type, 0) :
- (EulerObject *)PyObject_GC_New(EulerObject, &euler_Type);
+ eul_alloc = PyMem_Malloc(EULER_SIZE * sizeof(float));
+ if (UNLIKELY(eul_alloc == NULL)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Euler(): "
+ "problem allocating data");
+ return NULL;
+ }
+ self = BASE_MATH_NEW(EulerObject, euler_Type, base_type);
if (self) {
+ self->eul = eul_alloc;
+
/* init callbacks as NULL */
self->cb_user = NULL;
self->cb_type = self->cb_subtype = 0;
- if (type == Py_WRAP) {
- self->eul = eul;
- self->wrapped = Py_WRAP;
- }
- else if (type == Py_NEW) {
- self->eul = PyMem_Malloc(EULER_SIZE * sizeof(float));
- if (eul) {
- copy_v3_v3(self->eul, eul);
- }
- else {
- zero_v3(self->eul);
- }
-
- self->wrapped = Py_NEW;
+ if (eul) {
+ copy_v3_v3(self->eul, eul);
}
else {
- Py_FatalError("Euler(): invalid type!");
+ zero_v3(self->eul);
}
+ self->flag = BASE_MATH_FLAG_DEFAULT;
+ self->order = order;
+ }
+ else {
+ PyMem_Free(eul_alloc);
+ }
+
+ return (PyObject *)self;
+}
+
+PyObject *Euler_CreatePyObject_wrap(
+ float eul[3], const short order,
+ PyTypeObject *base_type)
+{
+ EulerObject *self;
+
+ self = BASE_MATH_NEW(EulerObject, euler_Type, base_type);
+ if (self) {
+ /* init callbacks as NULL */
+ self->cb_user = NULL;
+ self->cb_type = self->cb_subtype = 0;
+
+ self->eul = eul;
+ self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
+
self->order = order;
}
return (PyObject *)self;
}
-PyObject *Euler_CreatePyObject_cb(PyObject *cb_user, const short order,
- unsigned char cb_type, unsigned char cb_subtype)
+PyObject *Euler_CreatePyObject_cb(
+ PyObject *cb_user, const short order,
+ unsigned char cb_type, unsigned char cb_subtype)
{
- EulerObject *self = (EulerObject *)Euler_CreatePyObject(NULL, order, Py_NEW, NULL);
+ EulerObject *self = (EulerObject *)Euler_CreatePyObject(NULL, order, NULL);
if (self) {
Py_INCREF(cb_user);
self->cb_user = cb_user;
diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h
index 62fb83ef234..744f39faed1 100644
--- a/source/blender/python/mathutils/mathutils_Euler.h
+++ b/source/blender/python/mathutils/mathutils_Euler.h
@@ -43,9 +43,18 @@ typedef struct {
* blender (stored in blend_data). This is an either/or struct not both */
/* prototypes */
-PyObject *Euler_CreatePyObject(float eul[3], const short order, int type, PyTypeObject *base_type);
-PyObject *Euler_CreatePyObject_cb(PyObject *cb_user, const short order,
- unsigned char cb_type, unsigned char cb_subtype);
+PyObject *Euler_CreatePyObject(
+ const float eul[3], const short order,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT;
+PyObject *Euler_CreatePyObject_wrap(
+ float eul[3], const short order,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+PyObject *Euler_CreatePyObject_cb(
+ PyObject *cb_user, const short order,
+ unsigned char cb_type, unsigned char cb_subtype
+ ) ATTR_WARN_UNUSED_RESULT;
short euler_order_from_string(const char *str, const char *error_prefix);
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 282f29b4934..67905f8e340 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -32,6 +32,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/python_utildefines.h"
+
#ifndef MATH_STANDALONE
# include "BLI_string.h"
# include "BLI_dynstr.h"
@@ -109,7 +111,7 @@ static int mathutils_matrix_row_set(BaseMathObject *bmo, int row)
MatrixObject *self = (MatrixObject *)bmo->cb_user;
int col;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
return -1;
@@ -139,7 +141,7 @@ static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col)
{
MatrixObject *self = (MatrixObject *)bmo->cb_user;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
return -1;
@@ -198,7 +200,7 @@ static int mathutils_matrix_col_set(BaseMathObject *bmo, int col)
int num_row;
int row;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
return -1;
@@ -231,7 +233,7 @@ static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row)
{
MatrixObject *self = (MatrixObject *)bmo->cb_user;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
return -1;
@@ -284,7 +286,7 @@ static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col)
MatrixObject *self = (MatrixObject *)bmo->cb_user;
int row;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
for (row = 0; row < 3; row++) {
@@ -310,7 +312,7 @@ static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col,
{
MatrixObject *self = (MatrixObject *)bmo->cb_user;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
MATRIX_ITEM(self, row, col) = bmo->data[row];
@@ -344,7 +346,7 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
switch (PyTuple_GET_SIZE(args)) {
case 0:
- return Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, type);
+ return Matrix_CreatePyObject(NULL, 4, 4, type);
case 1:
{
PyObject *arg = PyTuple_GET_ITEM(args, 0);
@@ -363,7 +365,7 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (num_col >= 2 && num_col <= 4) {
/* sane row & col size, new matrix and assign as slice */
- PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, type);
+ PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, type);
if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
return matrix;
}
@@ -444,7 +446,7 @@ static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
return NULL;
}
- return Matrix_CreatePyObject(NULL, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
+ return Matrix_CreatePyObject(NULL, matSize, matSize, (PyTypeObject *)cls);
}
PyDoc_STRVAR(C_Matrix_Rotation_doc,
@@ -535,7 +537,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
matrix_3x3_as_4x4(mat);
}
/* pass to matrix creation */
- return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
+ return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
@@ -558,7 +560,7 @@ static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
return NULL;
- return Matrix_CreatePyObject(&mat[0][0], 4, 4, Py_NEW, (PyTypeObject *)cls);
+ return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
}
/* ----------------------------------mathutils.Matrix.Scale() ------------- */
/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
@@ -650,7 +652,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
matrix_3x3_as_4x4(mat);
}
/* pass to matrix creation */
- return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
+ return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
/* ----------------------------------mathutils.Matrix.OrthoProjection() --- */
/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
@@ -771,7 +773,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
matrix_3x3_as_4x4(mat);
}
/* pass to matrix creation */
- return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
+ return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
PyDoc_STRVAR(C_Matrix_Shear_doc,
@@ -874,7 +876,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
matrix_3x3_as_4x4(mat);
}
/* pass to matrix creation */
- return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
+ return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
void matrix_as_3x3(float mat[3][3], MatrixObject *self)
@@ -893,6 +895,19 @@ static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->num_col * mat_dst->num_row));
}
+/* transposes memory layout, rol/col's don't have to match */
+static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
+{
+ unsigned short col, row;
+ unsigned int i = 0;
+
+ for (row = 0; row < mat_src->num_row; row++) {
+ for (col = 0; col < mat_src->num_col; col++) {
+ mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col);
+ }
+ }
+}
+
/* assumes rowsize == colsize is checked and the read callback has run */
static float matrix_determinant_internal(const MatrixObject *self)
{
@@ -1078,7 +1093,7 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self)
mat4_to_quat(quat, (float (*)[4])self->matrix);
}
- return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
+ return Quaternion_CreatePyObject(quat, NULL);
}
/*---------------------------matrix.toEuler() --------------------*/
@@ -1152,7 +1167,7 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
else mat3_to_eulO(eul, order, mat);
}
- return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
+ return Euler_CreatePyObject(eul, order, NULL);
}
PyDoc_STRVAR(Matrix_resize_4x4_doc,
@@ -1165,7 +1180,7 @@ static PyObject *Matrix_resize_4x4(MatrixObject *self)
float mat[4][4];
int col;
- if (self->wrapped == Py_WRAP) {
+ if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_ValueError,
"Matrix.resize_4x4(): "
"cannot resize wrapped data - make a copy and resize that");
@@ -1214,12 +1229,12 @@ static PyObject *Matrix_to_4x4(MatrixObject *self)
return NULL;
if (self->num_row == 4 && self->num_col == 4) {
- return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self));
+ return Matrix_CreatePyObject(self->matrix, 4, 4, Py_TYPE(self));
}
else if (self->num_row == 3 && self->num_col == 3) {
float mat[4][4];
copy_m4_m3(mat, (float (*)[3])self->matrix);
- return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
+ return Matrix_CreatePyObject((float *)mat, 4, 4, Py_TYPE(self));
}
/* TODO, 2x2 matrix */
@@ -1252,15 +1267,15 @@ static PyObject *Matrix_to_3x3(MatrixObject *self)
matrix_as_3x3(mat, self);
- return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
+ return Matrix_CreatePyObject((float *)mat, 3, 3, Py_TYPE(self));
}
PyDoc_STRVAR(Matrix_to_translation_doc,
".. method:: to_translation()\n"
"\n"
-" Return a the translation part of a 4 row matrix.\n"
+" Return the translation part of a 4 row matrix.\n"
"\n"
-" :return: Return a the translation of a matrix.\n"
+" :return: Return the translation of a matrix.\n"
" :rtype: :class:`Vector`\n"
);
static PyObject *Matrix_to_translation(MatrixObject *self)
@@ -1275,15 +1290,15 @@ static PyObject *Matrix_to_translation(MatrixObject *self)
return NULL;
}
- return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, NULL);
}
PyDoc_STRVAR(Matrix_to_scale_doc,
".. method:: to_scale()\n"
"\n"
-" Return a the scale part of a 3x3 or 4x4 matrix.\n"
+" Return the scale part of a 3x3 or 4x4 matrix.\n"
"\n"
-" :return: Return a the scale of a matrix.\n"
+" :return: Return the scale of a matrix.\n"
" :rtype: :class:`Vector`\n"
"\n"
" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
@@ -1310,7 +1325,7 @@ static PyObject *Matrix_to_scale(MatrixObject *self)
/* compatible mat4_to_loc_rot_size */
mat3_to_rot_size(rot, size, mat);
- return Vector_CreatePyObject(size, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(size, 3, NULL);
}
/*---------------------------matrix.invert() ---------------------*/
@@ -1383,7 +1398,7 @@ PyDoc_STRVAR(Matrix_invert_doc,
);
static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (matrix_invert_is_compat(self) == false) {
@@ -1423,8 +1438,8 @@ PyDoc_STRVAR(Matrix_inverted_doc,
"\n"
" Return an inverted copy of the matrix.\n"
"\n"
-" :arg fallback: return this value when the inverse can't be calculated\n"
-" (instead of raising a :exc:`ValueError` exception).\n"
+" :arg fallback: return this when the inverse can't be calculated\n"
+" (instead of raising a :exc:`ValueError`).\n"
" :type fallback: any\n"
" :return: the inverted matrix or fallback when given.\n"
" :rtype: :class:`Matrix`\n"
@@ -1464,7 +1479,7 @@ static PyObject *Matrix_inverted(MatrixObject *self, PyObject *args)
static PyObject *Matrix_inverted_noargs(MatrixObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (matrix_invert_is_compat(self) == false) {
@@ -1494,7 +1509,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc,
);
static PyObject *Matrix_invert_safe(MatrixObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (matrix_invert_is_compat(self) == false) {
@@ -1545,7 +1560,7 @@ PyDoc_STRVAR(Matrix_adjugate_doc,
);
static PyObject *Matrix_adjugate(MatrixObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (self->num_col != self->num_row) {
@@ -1589,7 +1604,7 @@ static PyObject *Matrix_adjugated(MatrixObject *self)
PyDoc_STRVAR(Matrix_rotate_doc,
".. method:: rotate(other)\n"
"\n"
-" Rotates the matrix a by another mathutils value.\n"
+" Rotates the matrix by another mathutils value.\n"
"\n"
" :arg other: rotation component of mathutils value\n"
" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
@@ -1600,7 +1615,7 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
{
float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
@@ -1653,10 +1668,10 @@ static PyObject *Matrix_decompose(MatrixObject *self)
mat3_to_quat(quat, rot);
ret = PyTuple_New(3);
- PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, Py_NEW, NULL));
- PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, Py_NEW, NULL));
- PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, Py_NEW, NULL));
-
+ PyTuple_SET_ITEMS(ret,
+ Vector_CreatePyObject(loc, 3, NULL),
+ Quaternion_CreatePyObject(quat, NULL),
+ Vector_CreatePyObject(size, 3, NULL));
return ret;
}
@@ -1706,7 +1721,7 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
return NULL;
}
- return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
+ return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_TYPE(self));
}
/*---------------------------matrix.determinant() ----------------*/
@@ -1715,7 +1730,7 @@ PyDoc_STRVAR(Matrix_determinant_doc,
"\n"
" Return the determinant of a matrix.\n"
"\n"
-" :return: Return a the determinant of a matrix.\n"
+" :return: Return the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
@@ -1744,7 +1759,7 @@ PyDoc_STRVAR(Matrix_transpose_doc,
);
static PyObject *Matrix_transpose(MatrixObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (self->num_col != self->num_row) {
@@ -1791,7 +1806,7 @@ PyDoc_STRVAR(Matrix_normalize_doc,
);
static PyObject *Matrix_normalize(MatrixObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (self->num_col != self->num_row) {
@@ -1836,19 +1851,37 @@ PyDoc_STRVAR(Matrix_zero_doc,
"\n"
" Set all the matrix values to zero.\n"
"\n"
-" :return: an instance of itself\n"
" :rtype: :class:`Matrix`\n"
);
static PyObject *Matrix_zero(MatrixObject *self)
{
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return NULL;
+
fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
if (BaseMath_WriteCallback(self) == -1)
return NULL;
Py_RETURN_NONE;
+
}
/*---------------------------matrix.identity(() ------------------*/
+static void matrix_identity_internal(MatrixObject *self)
+{
+ BLI_assert((self->num_col == self->num_row) && (self->num_row <= 4));
+
+ if (self->num_col == 2) {
+ unit_m2((float (*)[2])self->matrix);
+ }
+ else if (self->num_col == 3) {
+ unit_m3((float (*)[3])self->matrix);
+ }
+ else {
+ unit_m4((float (*)[4])self->matrix);
+ }
+}
+
PyDoc_STRVAR(Matrix_identity_doc,
".. method:: identity()\n"
"\n"
@@ -1861,7 +1894,7 @@ PyDoc_STRVAR(Matrix_identity_doc,
);
static PyObject *Matrix_identity(MatrixObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (self->num_col != self->num_row) {
@@ -1871,15 +1904,7 @@ static PyObject *Matrix_identity(MatrixObject *self)
return NULL;
}
- if (self->num_col == 2) {
- unit_m2((float (*)[2])self->matrix);
- }
- else if (self->num_col == 3) {
- unit_m3((float (*)[3])self->matrix);
- }
- else {
- unit_m4((float (*)[4])self->matrix);
- }
+ matrix_identity_internal(self);
if (BaseMath_WriteCallback(self) == -1)
return NULL;
@@ -1891,7 +1916,7 @@ static PyObject *Matrix_identity(MatrixObject *self)
static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
{
- return Matrix_CreatePyObject((float *)matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
+ return Matrix_CreatePyObject((float *)matrix, self->num_col, self->num_row, Py_TYPE(self));
}
PyDoc_STRVAR(Matrix_copy_doc,
@@ -2025,7 +2050,22 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
return NULL;
}
- return Py_INCREF(res), res;
+ return Py_INCREF_RET(res);
+}
+
+static Py_hash_t Matrix_hash(MatrixObject *self)
+{
+ float mat[SQUARE(MATRIX_MAX_DIM)];
+
+ if (BaseMath_ReadCallback(self) == -1)
+ return -1;
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1)
+ return -1;
+
+ matrix_transpose_internal(mat, self);
+
+ return mathutils_array_hash(mat, self->num_row * self->num_col);
}
/*---------------------SEQUENCE PROTOCOLS------------------------
@@ -2040,7 +2080,7 @@ static int Matrix_len(MatrixObject *self)
* the wrapped vector gives direct access to the matrix data */
static PyObject *Matrix_item_row(MatrixObject *self, int row)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (row < 0 || row >= self->num_row) {
@@ -2054,7 +2094,7 @@ static PyObject *Matrix_item_row(MatrixObject *self, int row)
/* same but column access */
static PyObject *Matrix_item_col(MatrixObject *self, int col)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (col < 0 || col >= self->num_col) {
@@ -2073,7 +2113,7 @@ static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
{
int col;
float vec[MATRIX_MAX_DIM];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if (row >= self->num_row || row < 0) {
@@ -2098,7 +2138,7 @@ static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
{
int row;
float vec[MATRIX_MAX_DIM];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if (col >= self->num_col || col < 0) {
@@ -2150,7 +2190,7 @@ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *va
{
PyObject *value_fast = NULL;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
CLAMP(begin, 0, self->num_row);
@@ -2233,7 +2273,7 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
- return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
+ return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1));
}
/*------------------------obj - obj------------------------------
* subtraction */
@@ -2265,7 +2305,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
- return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
+ return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1));
}
/*------------------------obj * obj------------------------------
* multiplication */
@@ -2273,7 +2313,7 @@ static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
{
float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar);
- return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_NEW, Py_TYPE(mat));
+ return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_TYPE(mat));
}
static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
@@ -2317,7 +2357,7 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
}
}
- return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
+ return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
}
else if (mat2) {
/*FLOAT/INT * MATRIX */
@@ -2343,7 +2383,7 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
vec_size = mat1->num_row;
}
- return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2));
+ return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(m2));
}
/*FLOAT/INT * MATRIX */
else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
@@ -2516,7 +2556,7 @@ static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNU
{
float tvec[3];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
/*must be 4x4 square matrix*/
@@ -2652,6 +2692,7 @@ static PyGetSetDef Matrix_getseters[] = {
{(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL},
{(char *)"is_orthogonal_axis_vectors", (getter)Matrix_is_orthogonal_axis_vectors_get, (setter)NULL, Matrix_is_orthogonal_axis_vectors_doc, NULL},
{(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
+ {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -2695,6 +2736,9 @@ static struct PyMethodDef Matrix_methods[] = {
{"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
{"__deepcopy__", (PyCFunction) Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc},
+ /* base-math methods */
+ {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
+
/* class methods */
{"Identity", (PyCFunction) C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
{"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
@@ -2707,7 +2751,14 @@ static struct PyMethodDef Matrix_methods[] = {
/*------------------PY_OBECT DEFINITION--------------------------*/
PyDoc_STRVAR(matrix_doc,
-"This object gives access to Matrices in Blender."
+".. class:: Matrix([rows])\n"
+"\n"
+" This object gives access to Matrices in Blender, supporting square and rectangular\n"
+" matrices from 2x2 up to 4x4.\n"
+"\n"
+" :param rows: Sequence of rows.\n"
+" When ommitted, a 4x4 identity matrix is constructed.\n"
+" :type rows: 2d number sequence\n"
);
PyTypeObject matrix_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -2723,7 +2774,7 @@ PyTypeObject matrix_Type = {
&Matrix_NumMethods, /*tp_as_number*/
&Matrix_SeqMethods, /*tp_as_sequence*/
&Matrix_AsMapping, /*tp_as_mapping*/
- NULL, /*tp_hash*/
+ (hashfunc)Matrix_hash, /*tp_hash*/
NULL, /*tp_call*/
#ifndef MATH_STANDALONE
(reprfunc) Matrix_str, /*tp_str*/
@@ -2762,15 +2813,13 @@ PyTypeObject matrix_Type = {
NULL /*tp_del*/
};
-/* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- * (i.e. it was allocated elsewhere by MEM_mallocN())
- * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- * (i.e. it must be created here with PyMEM_malloc()) */
-PyObject *Matrix_CreatePyObject(float *mat,
- const unsigned short num_col, const unsigned short num_row,
- int type, PyTypeObject *base_type)
+PyObject *Matrix_CreatePyObject(
+ const float *mat,
+ const unsigned short num_col, const unsigned short num_row,
+ PyTypeObject *base_type)
{
MatrixObject *self;
+ float *mat_alloc;
/* matrix objects can be any 2-4row x 2-4col matrix */
if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
@@ -2780,10 +2829,17 @@ PyObject *Matrix_CreatePyObject(float *mat,
return NULL;
}
- self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) :
- (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type);
+ mat_alloc = PyMem_Malloc(num_col * num_row * sizeof(float));
+ if (UNLIKELY(mat_alloc == NULL)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Matrix(): "
+ "problem allocating data");
+ return NULL;
+ }
+ self = BASE_MATH_NEW(MatrixObject, matrix_Type, base_type);
if (self) {
+ self->matrix = mat_alloc;
self->num_col = num_col;
self->num_row = num_row;
@@ -2791,37 +2847,52 @@ PyObject *Matrix_CreatePyObject(float *mat,
self->cb_user = NULL;
self->cb_type = self->cb_subtype = 0;
- if (type == Py_WRAP) {
- self->matrix = mat;
- self->wrapped = Py_WRAP;
+ if (mat) { /*if a float array passed*/
+ memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
}
- else if (type == Py_NEW) {
- self->matrix = PyMem_Malloc(num_col * num_row * sizeof(float));
- if (self->matrix == NULL) { /*allocation failure*/
- PyErr_SetString(PyExc_MemoryError,
- "Matrix(): "
- "problem allocating pointer space");
- return NULL;
- }
-
- if (mat) { /*if a float array passed*/
- memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
- }
- else if (num_col == num_row) {
- /* or if no arguments are passed return identity matrix for square matrices */
- PyObject *ret_dummy = Matrix_identity(self);
- Py_DECREF(ret_dummy);
- }
- else {
- /* otherwise zero everything */
- memset(self->matrix, 0, num_col * num_row * sizeof(float));
- }
- self->wrapped = Py_NEW;
+ else if (num_col == num_row) {
+ /* or if no arguments are passed return identity matrix for square matrices */
+ matrix_identity_internal(self);
}
else {
- Py_FatalError("Matrix(): invalid type!");
- return NULL;
+ /* otherwise zero everything */
+ memset(self->matrix, 0, num_col * num_row * sizeof(float));
}
+ self->flag = BASE_MATH_FLAG_DEFAULT;
+ }
+ else {
+ PyMem_Free(mat_alloc);
+ }
+
+ return (PyObject *)self;
+}
+
+PyObject *Matrix_CreatePyObject_wrap(
+ float *mat,
+ const unsigned short num_col, const unsigned short num_row,
+ PyTypeObject *base_type)
+{
+ MatrixObject *self;
+
+ /* matrix objects can be any 2-4row x 2-4col matrix */
+ if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Matrix(): "
+ "row and column sizes must be between 2 and 4");
+ return NULL;
+ }
+
+ self = BASE_MATH_NEW(MatrixObject, matrix_Type, base_type);
+ if (self) {
+ self->num_col = num_col;
+ self->num_row = num_row;
+
+ /* init callbacks as NULL */
+ self->cb_user = NULL;
+ self->cb_type = self->cb_subtype = 0;
+
+ self->matrix = mat;
+ self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
}
return (PyObject *) self;
}
@@ -2830,7 +2901,7 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user,
const unsigned short num_col, const unsigned short num_row,
unsigned char cb_type, unsigned char cb_subtype)
{
- MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL);
+ MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, NULL);
if (self) {
Py_INCREF(cb_user);
self->cb_user = cb_user;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index f94af9e540e..9ae5a4bd61d 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -61,12 +61,21 @@ typedef struct {
* blender (stored in blend_data). This is an either/or struct not both */
/* prototypes */
-PyObject *Matrix_CreatePyObject(float *mat,
- const unsigned short num_col, const unsigned short num_row,
- int type, PyTypeObject *base_type);
-PyObject *Matrix_CreatePyObject_cb(PyObject *user,
- const unsigned short num_col, const unsigned short num_row,
- unsigned char cb_type, unsigned char cb_subtype);
+PyObject *Matrix_CreatePyObject(
+ const float *mat,
+ const unsigned short num_col, const unsigned short num_row,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT;
+PyObject *Matrix_CreatePyObject_wrap(
+ float *mat,
+ const unsigned short num_col, const unsigned short num_row,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+PyObject *Matrix_CreatePyObject_cb(
+ PyObject *user,
+ const unsigned short num_col, const unsigned short num_row,
+ unsigned char cb_type, unsigned char cb_subtype
+ ) ATTR_WARN_UNUSED_RESULT;
extern unsigned char mathutils_matrix_row_cb_index; /* default */
extern unsigned char mathutils_matrix_col_cb_index;
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index ae3476f5802..1752be6e306 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -32,6 +32,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/python_utildefines.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
@@ -121,7 +123,7 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
else quat_to_eulO(eul, order, tquat);
}
- return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
+ return Euler_CreatePyObject(eul, order, NULL);
}
PyDoc_STRVAR(Quaternion_to_matrix_doc,
@@ -140,7 +142,7 @@ static PyObject *Quaternion_to_matrix(QuaternionObject *self)
return NULL;
quat_to_mat3((float (*)[3])mat, self->quat);
- return Matrix_CreatePyObject(mat, 3, 3, Py_NEW, NULL);
+ return Matrix_CreatePyObject(mat, 3, 3, NULL);
}
PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
@@ -169,11 +171,36 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
quat__axis_angle_sanitize(axis, &angle);
ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(axis, 3, Py_NEW, NULL));
- PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(angle));
+ PyTuple_SET_ITEMS(ret,
+ Vector_CreatePyObject(axis, 3, NULL),
+ PyFloat_FromDouble(angle));
return ret;
}
+PyDoc_STRVAR(Quaternion_to_exponential_map_doc,
+".. method:: to_exponential_map()\n"
+"\n"
+" Return the exponential map representation of the quaternion.\n"
+"\n"
+" This representation consist of the rotation axis multiplied by the rotation angle."
+" Such a representation is useful for interpolation between multiple orientations.\n"
+"\n"
+" :return: exponential map.\n"
+" :rtype: :class:`Vector` of size 3\n"
+"\n"
+" To convert back to a quaternion, pass it to the :class:`Quaternion` constructor.\n"
+);
+static PyObject *Quaternion_to_exponential_map(QuaternionObject *self)
+{
+ float expmap[3];
+
+ if (BaseMath_ReadCallback(self) == -1)
+ return NULL;
+
+ quat_to_expmap(expmap, self->quat);
+ return Vector_CreatePyObject(expmap, 3, NULL);
+}
+
PyDoc_STRVAR(Quaternion_cross_doc,
".. method:: cross(other)\n"
"\n"
@@ -198,7 +225,7 @@ static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
}
mul_qt_qtqt(quat, self->quat, tquat);
- return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self));
+ return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
PyDoc_STRVAR(Quaternion_dot_doc,
@@ -252,7 +279,7 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject
rotation_between_quats_to_quat(quat, self->quat, tquat);
- return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self));
+ return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
PyDoc_STRVAR(Quaternion_slerp_doc,
@@ -297,13 +324,13 @@ static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
interp_qt_qtqt(quat, self->quat, tquat, fac);
- return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self));
+ return Quaternion_CreatePyObject(quat, Py_TYPE(self));
}
PyDoc_STRVAR(Quaternion_rotate_doc,
".. method:: rotate(other)\n"
"\n"
-" Rotates the quaternion a by another mathutils value.\n"
+" Rotates the quaternion by another mathutils value.\n"
"\n"
" :arg other: rotation component of mathutils value\n"
" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
@@ -313,7 +340,7 @@ static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
float tquat[4], length;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (mathutils_any_to_rotmat(other_rmat, value, "Quaternion.rotate(value)") == -1)
@@ -331,7 +358,8 @@ static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
}
/* ----------------------------Quaternion.normalize()---------------- */
-/* normalize the axis of rotation of [theta, vector] */
+/* Normalize the quaternion. This may change the angle as well as the
+ * rotation axis, as all of (w, x, y, z) are scaled. */
PyDoc_STRVAR(Quaternion_normalize_doc,
".. function:: normalize()\n"
"\n"
@@ -339,7 +367,7 @@ PyDoc_STRVAR(Quaternion_normalize_doc,
);
static PyObject *Quaternion_normalize(QuaternionObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
normalize_qt(self->quat);
@@ -367,7 +395,7 @@ PyDoc_STRVAR(Quaternion_invert_doc,
);
static PyObject *Quaternion_invert(QuaternionObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
invert_qt(self->quat);
@@ -393,12 +421,11 @@ PyDoc_STRVAR(Quaternion_identity_doc,
"\n"
" Set the quaternion to an identity quaternion.\n"
"\n"
-" :return: an instance of itself.\n"
" :rtype: :class:`Quaternion`\n"
);
static PyObject *Quaternion_identity(QuaternionObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
unit_qt(self->quat);
@@ -412,12 +439,11 @@ PyDoc_STRVAR(Quaternion_negate_doc,
"\n"
" Set the quaternion to its negative.\n"
"\n"
-" :return: an instance of itself.\n"
" :rtype: :class:`Quaternion`\n"
);
static PyObject *Quaternion_negate(QuaternionObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
mul_qt_fl(self->quat, -1.0f);
@@ -433,7 +459,7 @@ PyDoc_STRVAR(Quaternion_conjugate_doc,
);
static PyObject *Quaternion_conjugate(QuaternionObject *self)
{
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
conjugate_qt(self->quat);
@@ -470,7 +496,7 @@ static PyObject *Quaternion_copy(QuaternionObject *self)
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- return Quaternion_CreatePyObject(self->quat, Py_NEW, Py_TYPE(self));
+ return Quaternion_CreatePyObject(self->quat, Py_TYPE(self));
}
static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
{
@@ -546,7 +572,18 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
return NULL;
}
- return Py_INCREF(res), res;
+ return Py_INCREF_RET(res);
+}
+
+static Py_hash_t Quaternion_hash(QuaternionObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1)
+ return -1;
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1)
+ return -1;
+
+ return mathutils_array_hash(self->quat, QUAT_SIZE);
}
/* ---------------------SEQUENCE PROTOCOLS------------------------ */
@@ -579,8 +616,14 @@ static PyObject *Quaternion_item(QuaternionObject *self, int i)
/* sequence accessor (set) */
static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
{
- float scalar = (float)PyFloat_AsDouble(ob);
- if (scalar == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
+ float f;
+
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return -1;
+
+ f = (float)PyFloat_AsDouble(ob);
+
+ if (f == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
PyErr_SetString(PyExc_TypeError,
"quaternion[index] = x: "
"assigned value not a number");
@@ -595,7 +638,7 @@ static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
"array assignment index out of range");
return -1;
}
- self->quat[i] = scalar;
+ self->quat[i] = f;
if (BaseMath_WriteIndexCallback(self, i) == -1)
return -1;
@@ -631,7 +674,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
int i, size;
float quat[QUAT_SIZE];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
CLAMP(begin, 0, QUAT_SIZE);
@@ -750,7 +793,7 @@ static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
return NULL;
add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
- return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1));
+ return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
}
/* ------------------------obj - obj------------------------------ */
/* subtraction */
@@ -778,7 +821,7 @@ static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
quat[x] = quat1->quat[x] - quat2->quat[x];
}
- return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1));
+ return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
}
static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
@@ -786,7 +829,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
float tquat[4];
copy_qt_qt(tquat, quat->quat);
mul_qt_fl(tquat, scalar);
- return Quaternion_CreatePyObject(tquat, Py_NEW, Py_TYPE(quat));
+ return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
}
/*------------------------obj * obj------------------------------
@@ -809,7 +852,7 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
if (quat1 && quat2) { /* QUAT * QUAT (cross product) */
mul_qt_qtqt(quat, quat1->quat, quat2->quat);
- return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1));
+ return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
}
/* the only case this can happen (for a supported type is "FLOAT * QUAT") */
else if (quat2) { /* FLOAT * QUAT */
@@ -837,7 +880,7 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
copy_v3_v3(tvec, vec2->vec);
mul_qt_v3(quat1->quat, tvec);
- return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(vec2));
+ return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2));
}
/* QUAT * FLOAT */
else if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
@@ -865,7 +908,7 @@ static PyObject *Quaternion_neg(QuaternionObject *self)
return NULL;
negate_v4_v4(tquat, self->quat);
- return Quaternion_CreatePyObject(tquat, Py_NEW, Py_TYPE(self));
+ return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
}
@@ -978,7 +1021,7 @@ static int Quaternion_angle_set(QuaternionObject *self, PyObject *value, void *U
float axis[3], angle_dummy;
float angle;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
len = normalize_qt_qt(tquat, self->quat);
@@ -1023,7 +1066,7 @@ static PyObject *Quaternion_axis_vector_get(QuaternionObject *self, void *UNUSED
quat__axis_angle_sanitize(axis, NULL);
- return Vector_CreatePyObject(axis, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(axis, 3, NULL);
}
static int Quaternion_axis_vector_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
@@ -1034,7 +1077,7 @@ static int Quaternion_axis_vector_set(QuaternionObject *self, PyObject *value, v
float axis[3];
float angle;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
len = normalize_qt_qt(tquat, self->quat);
@@ -1075,9 +1118,24 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
case 0:
break;
case 1:
- if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq, "mathutils.Quaternion()") == -1)
+ {
+ int size;
+
+ if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) == -1) {
return NULL;
+ }
+
+ if (size == 4) {
+ /* 4d: Quaternion (common case) */
+ }
+ else {
+ /* 3d: Interpret as exponential map */
+ BLI_assert(size == 3);
+ expmap_to_quat(quat, quat);
+ }
+
break;
+ }
case 2:
{
float axis[3];
@@ -1089,7 +1147,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
/* PyArg_ParseTuple assures no more than 2 */
}
}
- return Quaternion_CreatePyObject(quat, Py_NEW, type);
+ return Quaternion_CreatePyObject(quat, type);
}
static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self)
@@ -1154,6 +1212,7 @@ static struct PyMethodDef Quaternion_methods[] = {
{"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
{"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
{"to_axis_angle", (PyCFunction) Quaternion_to_axis_angle, METH_NOARGS, Quaternion_to_axis_angle_doc},
+ {"to_exponential_map", (PyCFunction) Quaternion_to_exponential_map, METH_NOARGS, Quaternion_to_exponential_map_doc},
/* operation between 2 or more types */
{"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc},
@@ -1162,6 +1221,9 @@ static struct PyMethodDef Quaternion_methods[] = {
{"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc},
{"rotate", (PyCFunction) Quaternion_rotate, METH_O, Quaternion_rotate_doc},
+ /* base-math methods */
+ {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
+
{"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
{"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
{"__deepcopy__", (PyCFunction) Quaternion_deepcopy, METH_VARARGS, Quaternion_copy_doc},
@@ -1180,13 +1242,36 @@ static PyGetSetDef Quaternion_getseters[] = {
{(char *)"angle", (getter)Quaternion_angle_get, (setter)Quaternion_angle_set, Quaternion_angle_doc, NULL},
{(char *)"axis", (getter)Quaternion_axis_vector_get, (setter)Quaternion_axis_vector_set, Quaternion_axis_vector_doc, NULL},
{(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
+ {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(quaternion_doc,
-"This object gives access to Quaternions in Blender."
+".. class:: Quaternion([seq, [angle]])\n"
+"\n"
+" This object gives access to Quaternions in Blender.\n"
+"\n"
+" :param seq: size 3 or 4\n"
+" :type seq: :class:`Vector`\n"
+" :param angle: rotation angle, in radians\n"
+" :type angle: float\n"
+"\n"
+" The constructor takes arguments in various forms:\n"
+"\n"
+" (), *no args*\n"
+" Create an identity quaternion\n"
+" (*wxyz*)\n"
+" Create a quaternion from a ``(w, x, y, z)`` vector.\n"
+" (*exponential_map*)\n"
+" Create a quaternion from a 3d exponential map vector.\n"
+"\n"
+" .. seealso:: :meth:`to_exponential_map`\n"
+" (*axis, angle*)\n"
+" Create a quaternion representing a rotation of *angle* radians over *axis*.\n"
+"\n"
+" .. seealso:: :meth:`to_axis_angle`\n"
);
PyTypeObject quaternion_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -1202,7 +1287,7 @@ PyTypeObject quaternion_Type = {
&Quaternion_NumMethods, /* tp_as_number */
&Quaternion_SeqMethods, /* tp_as_sequence */
&Quaternion_AsMapping, /* tp_as_mapping */
- NULL, /* tp_hash */
+ (hashfunc)Quaternion_hash, /* tp_hash */
NULL, /* tp_call */
#ifndef MATH_STANDALONE
(reprfunc) Quaternion_str, /* tp_str */
@@ -1240,41 +1325,60 @@ PyTypeObject quaternion_Type = {
NULL, /* tp_weaklist */
NULL, /* tp_del */
};
-/* ------------------------Quaternion_CreatePyObject (internal)------------- */
-/* creates a new quaternion object */
-/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- * (i.e. it was allocated elsewhere by MEM_mallocN())
- * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- * (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *Quaternion_CreatePyObject(float quat[4], int type, PyTypeObject *base_type)
+
+PyObject *Quaternion_CreatePyObject(
+ const float quat[4],
+ PyTypeObject *base_type)
{
QuaternionObject *self;
+ float *quat_alloc;
- self = base_type ? (QuaternionObject *)base_type->tp_alloc(base_type, 0) :
- (QuaternionObject *)PyObject_GC_New(QuaternionObject, &quaternion_Type);
+ quat_alloc = PyMem_Malloc(QUAT_SIZE * sizeof(float));
+ if (UNLIKELY(quat_alloc == NULL)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Quaternion(): "
+ "problem allocating data");
+ return NULL;
+ }
+ self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
if (self) {
+ self->quat = quat_alloc;
/* init callbacks as NULL */
self->cb_user = NULL;
self->cb_type = self->cb_subtype = 0;
- if (type == Py_WRAP) {
- self->quat = quat;
- self->wrapped = Py_WRAP;
- }
- else if (type == Py_NEW) {
- self->quat = PyMem_Malloc(QUAT_SIZE * sizeof(float));
- if (!quat) { /* new empty */
- unit_qt(self->quat);
- }
- else {
- copy_qt_qt(self->quat, quat);
- }
- self->wrapped = Py_NEW;
+ /* NEW */
+ if (!quat) { /* new empty */
+ unit_qt(self->quat);
}
else {
- Py_FatalError("Quaternion(): invalid type!");
+ copy_qt_qt(self->quat, quat);
}
+ self->flag = BASE_MATH_FLAG_DEFAULT;
+ }
+ else {
+ PyMem_Free(quat_alloc);
+ }
+
+ return (PyObject *)self;
+}
+
+PyObject *Quaternion_CreatePyObject_wrap(
+ float quat[4],
+ PyTypeObject *base_type)
+{
+ QuaternionObject *self;
+
+ self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
+ if (self) {
+ /* init callbacks as NULL */
+ self->cb_user = NULL;
+ self->cb_type = self->cb_subtype = 0;
+
+ /* WRAP */
+ self->quat = quat;
+ self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
}
return (PyObject *) self;
}
@@ -1282,7 +1386,7 @@ PyObject *Quaternion_CreatePyObject(float quat[4], int type, PyTypeObject *base_
PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user,
unsigned char cb_type, unsigned char cb_subtype)
{
- QuaternionObject *self = (QuaternionObject *)Quaternion_CreatePyObject(NULL, Py_NEW, NULL);
+ QuaternionObject *self = (QuaternionObject *)Quaternion_CreatePyObject(NULL, NULL);
if (self) {
Py_INCREF(cb_user);
self->cb_user = cb_user;
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h
index 36036c6d3fa..66ee3362906 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.h
+++ b/source/blender/python/mathutils/mathutils_Quaternion.h
@@ -40,8 +40,17 @@ typedef struct {
* blender (stored in blend_data). This is an either/or struct not both */
/* prototypes */
-PyObject *Quaternion_CreatePyObject(float quat[4], int type, PyTypeObject *base_type);
-PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user,
- unsigned char cb_type, unsigned char cb_subtype);
+PyObject *Quaternion_CreatePyObject(
+ const float quat[4],
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT;
+PyObject *Quaternion_CreatePyObject_wrap(
+ float quat[4],
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+PyObject *Quaternion_CreatePyObject_cb(
+ PyObject *cb_user,
+ unsigned char cb_type, unsigned char cb_subtype
+ ) ATTR_WARN_UNUSED_RESULT;
#endif /* __MATHUTILS_QUATERNION_H__ */
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 15a9860be0a..a33b55c35dc 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -336,6 +336,9 @@ PyDoc_STRVAR(Vector_zero_doc,
);
static PyObject *Vector_zero(VectorObject *self)
{
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return NULL;
+
fill_vn_fl(self->vec, self->size, 0.0f);
if (BaseMath_WriteCallback(self) == -1)
@@ -357,7 +360,7 @@ PyDoc_STRVAR(Vector_normalize_doc,
static PyObject *Vector_normalize(VectorObject *self)
{
int size = (self->size == 4 ? 3 : self->size);
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
normalize_vn(self->vec, size);
@@ -387,7 +390,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value)
{
int size;
- if (self->wrapped == Py_WRAP) {
+ if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize(): "
"cannot resize wrapped data - only python vectors");
@@ -475,7 +478,7 @@ PyDoc_STRVAR(Vector_resize_2d_doc,
);
static PyObject *Vector_resize_2d(VectorObject *self)
{
- if (self->wrapped == Py_WRAP) {
+ if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_2d(): "
"cannot resize wrapped data - only python vectors");
@@ -507,7 +510,7 @@ PyDoc_STRVAR(Vector_resize_3d_doc,
);
static PyObject *Vector_resize_3d(VectorObject *self)
{
- if (self->wrapped == Py_WRAP) {
+ if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_3d(): "
"cannot resize wrapped data - only python vectors");
@@ -542,7 +545,7 @@ PyDoc_STRVAR(Vector_resize_4d_doc,
);
static PyObject *Vector_resize_4d(VectorObject *self)
{
- if (self->wrapped == Py_WRAP) {
+ if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_4d(): "
"cannot resize wrapped data - only python vectors");
@@ -586,7 +589,7 @@ static PyObject *Vector_to_2d(VectorObject *self)
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- return Vector_CreatePyObject(self->vec, 2, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(self->vec, 2, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_to_3d_doc,
".. method:: to_3d()\n"
@@ -604,7 +607,7 @@ static PyObject *Vector_to_3d(VectorObject *self)
return NULL;
memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 3));
- return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(tvec, 3, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_to_4d_doc,
".. method:: to_4d()\n"
@@ -622,7 +625,7 @@ static PyObject *Vector_to_4d(VectorObject *self)
return NULL;
memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 4));
- return Vector_CreatePyObject(tvec, 4, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(tvec, 4, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_to_tuple_doc,
@@ -797,7 +800,7 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
vec_to_quat(quat, vec, track, up);
- return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
+ return Quaternion_CreatePyObject(quat, NULL);
}
PyDoc_STRVAR(Vector_orthogonal_doc,
@@ -829,7 +832,7 @@ static PyObject *Vector_orthogonal(VectorObject *self)
else
ortho_v2_v2(vec, self->vec);
- return Vector_CreatePyObject(vec, self->size, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(vec, self->size, Py_TYPE(self));
}
@@ -877,7 +880,7 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
normalize_v3(mirror);
reflect_v3_v3v3(reflect, vec, mirror);
- return Vector_CreatePyObject(reflect, self->size, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(reflect, self->size, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_cross_doc,
@@ -910,7 +913,7 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value)
return NULL;
if (self->size == 3) {
- ret = Vector_CreatePyObject(NULL, 3, Py_NEW, Py_TYPE(self));
+ ret = Vector_CreatePyObject(NULL, 3, Py_TYPE(self));
cross_v3_v3v3(((VectorObject *)ret)->vec, self->vec, tvec);
}
else {
@@ -954,13 +957,11 @@ PyDoc_STRVAR(Vector_angle_doc,
"\n"
" :arg other: another vector to compare the angle with\n"
" :type other: :class:`Vector`\n"
-" :arg fallback: return this value when the angle can't be calculated\n"
-" (zero length vector)\n"
+" :arg fallback: return this when the angle can't be calculated (zero length vector),\n"
+" (instead of raising a :exc:`ValueError`).\n"
" :type fallback: any\n"
" :return: angle in radians or fallback when given\n"
" :rtype: float\n"
-"\n"
-" .. note:: Zero length vectors raise an :exc:`ValueError`.\n"
);
static PyObject *Vector_angle(VectorObject *self, PyObject *args)
{
@@ -1018,13 +1019,11 @@ PyDoc_STRVAR(Vector_angle_signed_doc,
"\n"
" :arg other: another vector to compare the angle with\n"
" :type other: :class:`Vector`\n"
-" :arg fallback: return this value when the angle can't be calculated\n"
-" (zero length vector)\n"
+" :arg fallback: return this when the angle can't be calculated (zero length vector),\n"
+" (instead of raising a :exc:`ValueError`).\n"
" :type fallback: any\n"
" :return: angle in radians or fallback when given\n"
" :rtype: float\n"
-"\n"
-" .. note:: Zero length vectors raise an :exc:`ValueError`.\n"
);
static PyObject *Vector_angle_signed(VectorObject *self, PyObject *args)
{
@@ -1102,7 +1101,7 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value)
rotation_between_vecs_to_quat(quat, vec_a, vec_b);
- return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
+ return Quaternion_CreatePyObject(quat, NULL);
}
PyDoc_STRVAR(Vector_project_doc,
@@ -1123,9 +1122,6 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
double dot = 0.0f, dot2 = 0.0f;
int x;
- if (BaseMath_ReadCallback(self) == -1)
- return NULL;
-
if (mathutils_array_parse(tvec, size, size, value, "Vector.project(other), invalid 'other' arg") == -1)
return NULL;
@@ -1148,7 +1144,7 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
for (x = 0; x < size; x++) {
vec[x] = (float)dot * tvec[x];
}
- return Vector_CreatePyObject(vec, size, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(vec, size, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_lerp_doc,
@@ -1167,9 +1163,8 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
{
const int size = self->size;
PyObject *value = NULL;
- float fac, ifac;
- float *tvec, *vec;
- int x;
+ float fac;
+ float *tvec;
if (!PyArg_ParseTuple(args, "Of:lerp", &value, &fac))
return NULL;
@@ -1182,23 +1177,9 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
return NULL;
}
- vec = PyMem_Malloc(size * sizeof(float));
- if (vec == NULL) {
- PyErr_SetString(PyExc_MemoryError,
- "Vector.lerp(): "
- "problem allocating pointer space");
- return NULL;
- }
-
- ifac = 1.0f - fac;
-
- for (x = 0; x < size; x++) {
- vec[x] = (ifac * self->vec[x]) + (fac * tvec[x]);
- }
-
- PyMem_Free(tvec);
+ interp_vn_vn(tvec, self->vec, 1.0f - fac, size);
- return Vector_CreatePyObject_alloc(vec, size, Py_TYPE(self));
+ return Vector_CreatePyObject_alloc(tvec, size, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_slerp_doc,
@@ -1210,8 +1191,8 @@ PyDoc_STRVAR(Vector_slerp_doc,
" :type other: :class:`Vector`\n"
" :arg factor: The interpolation value typically in [0.0, 1.0].\n"
" :type factor: float\n"
-" :arg fallback: return this value when the vector can't be calculated\n"
-" (zero length vector or direct opposites)\n"
+" :arg fallback: return this when the vector can't be calculated (zero length vector or direct opposites),\n"
+" (instead of raising a :exc:`ValueError`).\n"
" :type fallback: any\n"
" :return: The interpolated vector.\n"
" :rtype: :class:`Vector`\n"
@@ -1287,7 +1268,7 @@ static PyObject *Vector_slerp(VectorObject *self, PyObject *args)
ret_vec[x] = (w[0] * self_vec[x]) + (w[1] * other_vec[x]);
}
- return Vector_CreatePyObject(ret_vec, size, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(ret_vec, size, Py_TYPE(self));
}
PyDoc_STRVAR(Vector_rotate_doc,
@@ -1302,7 +1283,7 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
{
float other_rmat[3][3];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return NULL;
if (mathutils_any_to_rotmat(other_rmat, value, "Vector.rotate(value)") == -1)
@@ -1336,7 +1317,7 @@ static PyObject *Vector_copy(VectorObject *self)
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- return Vector_CreatePyObject(self->vec, self->size, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(self->vec, self->size, Py_TYPE(self));
}
static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args)
{
@@ -1420,6 +1401,10 @@ static PyObject *Vector_item(VectorObject *self, int i)
static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const bool is_attr)
{
float scalar;
+
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return -1;
+
if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
PyErr_SetString(PyExc_TypeError,
"vector[index] = x: "
@@ -1481,7 +1466,7 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
int size = 0;
float *vec = NULL;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
CLAMP(begin, 0, self->size);
@@ -1540,8 +1525,7 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2)
}
vec = PyMem_Malloc(vec1->size * sizeof(float));
-
- if (vec == NULL) { /*allocation failure*/
+ if (vec == NULL) {
PyErr_SetString(PyExc_MemoryError,
"Vector(): "
"problem allocating pointer space");
@@ -1575,7 +1559,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
return NULL;
}
- if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1)
+ if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1)
return NULL;
add_vn_vn(vec1->vec, vec2->vec, vec1->size);
@@ -1612,8 +1596,7 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
}
vec = PyMem_Malloc(vec1->size * sizeof(float));
-
- if (vec == NULL) { /*allocation failure*/
+ if (vec == NULL) {
PyErr_SetString(PyExc_MemoryError,
"Vector(): "
"problem allocating pointer space");
@@ -1647,7 +1630,7 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
return NULL;
}
- if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1)
+ if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1)
return NULL;
sub_vn_vn(vec1->vec, vec2->vec, vec1->size);
@@ -1705,8 +1688,7 @@ int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec,
static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
{
float *tvec = PyMem_Malloc(vec->size * sizeof(float));
-
- if (tvec == NULL) { /*allocation failure*/
+ if (tvec == NULL) {
PyErr_SetString(PyExc_MemoryError,
"vec * float: "
"problem allocating pointer space");
@@ -1765,7 +1747,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
vec_size = ((MatrixObject *)v2)->num_col;
}
- return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(vec1));
+ return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1));
}
else if (QuaternionObject_Check(v2)) {
/* VEC * QUAT */
@@ -1791,7 +1773,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
copy_v3_v3(tvec, vec1->vec);
mul_qt_v3(quat2->quat, tvec);
- return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(vec1));
+ return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec1));
#endif
/* ------ to be removed ------*/
}
@@ -1821,7 +1803,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
VectorObject *vec = (VectorObject *)v1;
float scalar;
- if (BaseMath_ReadCallback(vec) == -1)
+ if (BaseMath_ReadCallback_ForWrite(vec) == -1)
return NULL;
/* only support vec*=float and vec*=mat
@@ -1923,7 +1905,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
vec = PyMem_Malloc(vec1->size * sizeof(float));
- if (vec == NULL) { /*allocation failure*/
+ if (vec == NULL) {
PyErr_SetString(PyExc_MemoryError,
"vec / value: "
"problem allocating pointer space");
@@ -1941,7 +1923,7 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
float scalar;
VectorObject *vec1 = (VectorObject *)v1;
- if (BaseMath_ReadCallback(vec1) == -1)
+ if (BaseMath_ReadCallback_ForWrite(vec1) == -1)
return NULL;
if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
@@ -2065,6 +2047,17 @@ static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int compa
}
}
+static Py_hash_t Vector_hash(VectorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1)
+ return -1;
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1)
+ return -1;
+
+ return mathutils_array_hash(self->vec, self->size);
+}
+
/*-----------------PROTCOL DECLARATIONS--------------------------*/
static PySequenceMethods Vector_SeqMethods = {
(lenfunc) Vector_len, /* sq_length */
@@ -2228,7 +2221,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
{
double dot = 0.0f, param;
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
if ((param = PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred()) {
@@ -2308,7 +2301,7 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure)
axis_to++;
}
- return Vector_CreatePyObject(vec, axis_to, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject(vec, axis_to, Py_TYPE(self));
}
/* Set the items of this vector using a swizzle.
@@ -2334,7 +2327,7 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
float tvec[MAX_DIMENSIONS];
float vec_assign[MAX_DIMENSIONS];
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback_ForWrite(self) == -1)
return -1;
/* Check that the closure can be used with this vector: even 2D vectors have
@@ -2415,6 +2408,7 @@ static PyGetSetDef Vector_getseters[] = {
{(char *)"length_squared", (getter)Vector_length_squared_get, (setter)NULL, Vector_length_squared_doc, NULL},
{(char *)"magnitude", (getter)Vector_length_get, (setter)Vector_length_set, Vector_length_doc, NULL},
{(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
+ {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
/* autogenerated swizzle attrs, see python script below */
@@ -2893,6 +2887,9 @@ static struct PyMethodDef Vector_methods[] = {
{"slerp", (PyCFunction) Vector_slerp, METH_VARARGS, Vector_slerp_doc},
{"rotate", (PyCFunction) Vector_rotate, METH_O, Vector_rotate_doc},
+ /* base-math methods */
+ {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
+
{"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc},
{"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
{"__deepcopy__", (PyCFunction) Vector_deepcopy, METH_VARARGS, NULL},
@@ -2907,7 +2904,12 @@ static struct PyMethodDef Vector_methods[] = {
*/
PyDoc_STRVAR(vector_doc,
-"This object gives access to Vectors in Blender."
+".. class:: Vector(seq)\n"
+"\n"
+" This object gives access to Vectors in Blender.\n"
+"\n"
+" :param seq: Components of the vector, must be a sequence of at least two\n"
+" :type seq: sequence of numbers\n"
);
PyTypeObject vector_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -2933,7 +2935,7 @@ PyTypeObject vector_Type = {
/* More standard operations (here for binary compatibility) */
- NULL, /* hashfunc tp_hash; */
+ (hashfunc)Vector_hash, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
#ifndef MATH_STANDALONE
(reprfunc)Vector_str, /* reprfunc tp_str; */
@@ -2994,15 +2996,12 @@ PyTypeObject vector_Type = {
NULL
};
-/*------------------------Vector_CreatePyObject (internal)-------------
- * creates a new vector object
- * pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- * (i.e. it was allocated elsewhere by MEM_mallocN())
- * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- * (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTypeObject *base_type)
+PyObject *Vector_CreatePyObject(
+ const float *vec, const int size,
+ PyTypeObject *base_type)
{
VectorObject *self;
+ float *vec_alloc;
if (size < 2) {
PyErr_SetString(PyExc_RuntimeError,
@@ -3010,44 +3009,72 @@ PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTy
return NULL;
}
- self = base_type ? (VectorObject *)base_type->tp_alloc(base_type, 0) :
- (VectorObject *)PyObject_GC_New(VectorObject, &vector_Type);
+ vec_alloc = PyMem_Malloc(size * sizeof(float));
+ if (UNLIKELY(vec_alloc == NULL)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector(): "
+ "problem allocating data");
+ return NULL;
+ }
+ self = BASE_MATH_NEW(VectorObject, vector_Type, base_type);
if (self) {
+ self->vec = vec_alloc;
self->size = size;
/* init callbacks as NULL */
self->cb_user = NULL;
self->cb_type = self->cb_subtype = 0;
- if (type == Py_WRAP) {
- self->vec = vec;
- self->wrapped = Py_WRAP;
+ if (vec) {
+ memcpy(self->vec, vec, size * sizeof(float));
}
- else if (type == Py_NEW) {
- self->vec = PyMem_Malloc(size * sizeof(float));
- if (vec) {
- memcpy(self->vec, vec, size * sizeof(float));
+ else { /* new empty */
+ fill_vn_fl(self->vec, size, 0.0f);
+ if (size == 4) { /* do the homogeneous thing */
+ self->vec[3] = 1.0f;
}
- else { /* new empty */
- fill_vn_fl(self->vec, size, 0.0f);
- if (size == 4) { /* do the homogeneous thing */
- self->vec[3] = 1.0f;
- }
- }
- self->wrapped = Py_NEW;
- }
- else {
- Py_FatalError("Vector(): invalid type!");
}
+ self->flag = BASE_MATH_FLAG_DEFAULT;
+ }
+ else {
+ PyMem_Free(vec_alloc);
+ }
+
+ return (PyObject *)self;
+}
+
+PyObject *Vector_CreatePyObject_wrap(
+ float *vec, const int size,
+ PyTypeObject *base_type)
+{
+ VectorObject *self;
+
+ if (size < 2) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Vector(): invalid size");
+ return NULL;
+ }
+
+ self = BASE_MATH_NEW(VectorObject, vector_Type, base_type);
+ if (self) {
+ self->size = size;
+
+ /* init callbacks as NULL */
+ self->cb_user = NULL;
+ self->cb_type = self->cb_subtype = 0;
+
+ self->vec = vec;
+ self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
}
return (PyObject *) self;
}
-PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, unsigned char cb_type, unsigned char cb_subtype)
+PyObject *Vector_CreatePyObject_cb(
+ PyObject *cb_user, int size,
+ unsigned char cb_type, unsigned char cb_subtype)
{
- float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* dummy init vector, callbacks will be used on access */
- VectorObject *self = (VectorObject *)Vector_CreatePyObject(dummy, size, Py_NEW, NULL);
+ VectorObject *self = (VectorObject *)Vector_CreatePyObject(NULL, size, NULL);
if (self) {
Py_INCREF(cb_user);
self->cb_user = cb_user;
@@ -3059,11 +3086,15 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, unsigned char cb
return (PyObject *)self;
}
-PyObject *Vector_CreatePyObject_alloc(const float *vec, const int size, PyTypeObject *base_type)
+PyObject *Vector_CreatePyObject_alloc(
+ float *vec, const int size,
+ PyTypeObject *base_type)
{
- VectorObject *vect_ob;
- vect_ob = (VectorObject *)Vector_CreatePyObject((float *)vec, size, Py_WRAP, base_type);
- vect_ob->wrapped = Py_NEW;
+ VectorObject *self;
+ self = (VectorObject *)Vector_CreatePyObject_wrap(vec, size, base_type);
+ if (self) {
+ self->flag = BASE_MATH_FLAG_DEFAULT;
+ }
- return (PyObject *)vect_ob;
+ return (PyObject *)self;
}
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 2074270670a..74ca3336f4b 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -34,13 +34,25 @@ extern PyTypeObject vector_Type;
typedef struct {
BASE_MATH_MEMBERS(vec);
- int size; /* vec size 2,3 or 4 */
+ int size; /* vec size 2 or more */
} VectorObject;
/*prototypes*/
-PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTypeObject *base_type);
-PyObject *Vector_CreatePyObject_cb(PyObject *user, int size,
- unsigned char cb_type, unsigned char subtype);
-PyObject *Vector_CreatePyObject_alloc(const float *vec, const int size, PyTypeObject *base_type);
+PyObject *Vector_CreatePyObject(
+ const float *vec, const int size,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT;
+PyObject *Vector_CreatePyObject_wrap(
+ float *vec, const int size,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+PyObject *Vector_CreatePyObject_cb(
+ PyObject *user, int size,
+ unsigned char cb_type, unsigned char subtype
+ ) ATTR_WARN_UNUSED_RESULT;
+PyObject *Vector_CreatePyObject_alloc(
+ float *vec, const int size,
+ PyTypeObject *base_type
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
#endif /* __MATHUTILS_VECTOR_H__ */
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 0f0ffe9fec5..bb4080decef 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -42,6 +42,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/python_utildefines.h"
/*-------------------------DOC STRINGS ---------------------------*/
PyDoc_STRVAR(M_Geometry_doc,
@@ -72,48 +73,37 @@ PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc,
);
static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
- float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
+ const char *error_prefix = "intersect_ray_tri";
+ PyObject *py_ray, *py_ray_off, *py_tri[3];
+ float dir[3], orig[3], tri[3][3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
float det, inv_det, u, v, t;
int clip = 1;
+ int i;
- if (!PyArg_ParseTuple(args,
- "O!O!O!O!O!|i:intersect_ray_tri",
- &vector_Type, &vec1,
- &vector_Type, &vec2,
- &vector_Type, &vec3,
- &vector_Type, &ray,
- &vector_Type, &ray_off, &clip))
+ if (!PyArg_ParseTuple(
+ args, "OOOOO|i:intersect_ray_tri",
+ UNPACK3_EX(&, py_tri, ), &py_ray, &py_ray_off, &clip))
{
return NULL;
}
- if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
- PyErr_SetString(PyExc_ValueError,
- "only 3D vectors for all parameters");
- return NULL;
- }
- if (BaseMath_ReadCallback(vec1) == -1 ||
- BaseMath_ReadCallback(vec2) == -1 ||
- BaseMath_ReadCallback(vec3) == -1 ||
- BaseMath_ReadCallback(ray) == -1 ||
- BaseMath_ReadCallback(ray_off) == -1)
+ if (((mathutils_array_parse(dir, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_ray, error_prefix) != -1) &&
+ (mathutils_array_parse(orig, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_ray_off, error_prefix) != -1)) == 0)
{
return NULL;
}
- copy_v3_v3(v1, vec1->vec);
- copy_v3_v3(v2, vec2->vec);
- copy_v3_v3(v3, vec3->vec);
+ for (i = 0; i < ARRAY_SIZE(tri); i++) {
+ if (mathutils_array_parse(tri[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_tri[i], error_prefix) == -1) {
+ return NULL;
+ }
+ }
- copy_v3_v3(dir, ray->vec);
normalize_v3(dir);
- copy_v3_v3(orig, ray_off->vec);
-
/* find vectors for two edges sharing v1 */
- sub_v3_v3v3(e1, v2, v1);
- sub_v3_v3v3(e2, v3, v1);
+ sub_v3_v3v3(e1, tri[1], tri[0]);
+ sub_v3_v3v3(e2, tri[2], tri[0]);
/* begin calculating determinant - also used to calculated U parameter */
cross_v3_v3v3(pvec, dir, e2);
@@ -128,7 +118,7 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *
inv_det = 1.0f / det;
/* calculate distance from v1 to ray origin */
- sub_v3_v3v3(tvec, orig, v1);
+ sub_v3_v3v3(tvec, orig, tri[0]);
/* calculate U parameter and test bounds */
u = dot_v3v3(tvec, pvec) * inv_det;
@@ -157,7 +147,7 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *
mul_v3_fl(dir, t);
add_v3_v3v3(pvec, orig, dir);
- return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(pvec, 3, NULL);
}
/* Line-Line intersection using algorithm from mathworld.wolfram.com */
@@ -179,82 +169,45 @@ PyDoc_STRVAR(M_Geometry_intersect_line_line_doc,
);
static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject *args)
{
+ const char *error_prefix = "intersect_line_line";
PyObject *tuple;
- VectorObject *vec1, *vec2, *vec3, *vec4;
- float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
-
- if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line",
- &vector_Type, &vec1,
- &vector_Type, &vec2,
- &vector_Type, &vec3,
- &vector_Type, &vec4))
+ PyObject *py_lines[4];
+ float lines[4][3], i1[3], i2[3];
+ int len;
+ int result;
+
+ if (!PyArg_ParseTuple(
+ args, "OOOO:intersect_line_line",
+ UNPACK4_EX(&, py_lines, )))
{
return NULL;
}
- if (vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) {
- PyErr_SetString(PyExc_ValueError,
- "vectors must be of the same size");
- return NULL;
- }
-
- if (BaseMath_ReadCallback(vec1) == -1 ||
- BaseMath_ReadCallback(vec2) == -1 ||
- BaseMath_ReadCallback(vec3) == -1 ||
- BaseMath_ReadCallback(vec4) == -1)
+ if ((((len = mathutils_array_parse(lines[0], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[0], error_prefix)) != -1) &&
+ (mathutils_array_parse(lines[1], len, len | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[1], error_prefix) != -1) &&
+ (mathutils_array_parse(lines[2], len, len | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[2], error_prefix) != -1) &&
+ (mathutils_array_parse(lines[3], len, len | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[3], error_prefix) != -1)) == 0)
{
return NULL;
}
- if (vec1->size == 3 || vec1->size == 2) {
- int result;
-
- if (vec1->size == 3) {
- copy_v3_v3(v1, vec1->vec);
- copy_v3_v3(v2, vec2->vec);
- copy_v3_v3(v3, vec3->vec);
- copy_v3_v3(v4, vec4->vec);
- }
- else {
- v1[0] = vec1->vec[0];
- v1[1] = vec1->vec[1];
- v1[2] = 0.0f;
-
- v2[0] = vec2->vec[0];
- v2[1] = vec2->vec[1];
- v2[2] = 0.0f;
-
- v3[0] = vec3->vec[0];
- v3[1] = vec3->vec[1];
- v3[2] = 0.0f;
-
- v4[0] = vec4->vec[0];
- v4[1] = vec4->vec[1];
- v4[2] = 0.0f;
- }
-
- result = isect_line_line_v3(v1, v2, v3, v4, i1, i2);
- /* The return-code isnt exposed,
- * this way we can check know how close the lines are. */
- if (result == 1) {
- closest_to_line_v3(i2, i1, v3, v4);
- }
+ result = isect_line_line_v3(UNPACK4(lines), i1, i2);
+ /* The return-code isnt exposed,
+ * this way we can check know how close the lines are. */
+ if (result == 1) {
+ closest_to_line_v3(i2, i1, lines[2], lines[3]);
+ }
- if (result == 0) {
- /* colinear */
- Py_RETURN_NONE;
- }
- else {
- tuple = PyTuple_New(2);
- PyTuple_SET_ITEM(tuple, 0, Vector_CreatePyObject(i1, vec1->size, Py_NEW, NULL));
- PyTuple_SET_ITEM(tuple, 1, Vector_CreatePyObject(i2, vec1->size, Py_NEW, NULL));
- return tuple;
- }
+ if (result == 0) {
+ /* colinear */
+ Py_RETURN_NONE;
}
else {
- PyErr_SetString(PyExc_ValueError,
- "2D/3D vectors only");
- return NULL;
+ tuple = PyTuple_New(2);
+ PyTuple_SET_ITEMS(tuple,
+ Vector_CreatePyObject(i1, len, NULL),
+ Vector_CreatePyObject(i2, len, NULL));
+ return tuple;
}
}
@@ -277,31 +230,30 @@ PyDoc_STRVAR(M_Geometry_intersect_sphere_sphere_2d_doc,
);
static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), PyObject *args)
{
+ const char *error_prefix = "intersect_sphere_sphere_2d";
PyObject *ret;
- VectorObject *vec_a, *vec_b;
- const float *v_a, *v_b;
+ PyObject *py_v_a, *py_v_b;
+ float v_a[2], v_b[2];
float rad_a, rad_b;
float v_ab[2];
float dist;
- if (!PyArg_ParseTuple(args, "O!fO!f:intersect_sphere_sphere_2d",
- &vector_Type, &vec_a, &rad_a,
- &vector_Type, &vec_b, &rad_b))
+ if (!PyArg_ParseTuple(
+ args, "OfOf:intersect_sphere_sphere_2d",
+ &py_v_a, &rad_a,
+ &py_v_b, &rad_b))
{
return NULL;
}
- if (BaseMath_ReadCallback(vec_a) == -1 ||
- BaseMath_ReadCallback(vec_b) == -1)
+ if (((mathutils_array_parse(v_a, 2, 2, py_v_a, error_prefix) != -1) &&
+ (mathutils_array_parse(v_b, 2, 2, py_v_b, error_prefix) != -1)) == 0)
{
return NULL;
}
ret = PyTuple_New(2);
- v_a = vec_a->vec;
- v_b = vec_b->vec;
-
sub_v2_v2v2(v_ab, v_b, v_a);
dist = len_v2(v_ab);
@@ -313,8 +265,9 @@ static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), P
(dist < FLT_EPSILON))
{
/* out of range */
- PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None);
- PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None);
+ PyTuple_SET_ITEMS(ret,
+ Py_INCREF_RET(Py_None),
+ Py_INCREF_RET(Py_None));
}
else {
const float dist_delta = ((rad_a * rad_a) - (rad_b * rad_b) + (dist * dist)) / (2.0f * dist);
@@ -331,94 +284,51 @@ static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), P
i2[0] = i_cent[0] - h * v_ab[1] / dist;
i2[1] = i_cent[1] + h * v_ab[0] / dist;
- PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(i1, 2, Py_NEW, NULL));
- PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(i2, 2, Py_NEW, NULL));
+ PyTuple_SET_ITEMS(ret,
+ Vector_CreatePyObject(i1, 2, NULL),
+ Vector_CreatePyObject(i2, 2, NULL));
}
return ret;
}
PyDoc_STRVAR(M_Geometry_normal_doc,
-".. function:: normal(v1, v2, v3, v4=None)\n"
+".. function:: normal(vectors)\n"
"\n"
-" Returns the normal of the 3D tri or quad.\n"
+" Returns the normal of a 3D polygon.\n"
"\n"
-" :arg v1: Point1\n"
-" :type v1: :class:`mathutils.Vector`\n"
-" :arg v2: Point2\n"
-" :type v2: :class:`mathutils.Vector`\n"
-" :arg v3: Point3\n"
-" :type v3: :class:`mathutils.Vector`\n"
-" :arg v4: Point4 (optional)\n"
-" :type v4: :class:`mathutils.Vector`\n"
+" :arg vectors: Vectors to calculate normals with\n"
+" :type vectors: sequence of 3 or more 3d vector\n"
" :rtype: :class:`mathutils.Vector`\n"
);
static PyObject *M_Geometry_normal(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *vec1, *vec2, *vec3, *vec4;
+ float (*coords)[3];
+ int coords_len;
float n[3];
+ PyObject *ret = NULL;
- if (PyTuple_GET_SIZE(args) == 3) {
- if (!PyArg_ParseTuple(args, "O!O!O!:normal",
- &vector_Type, &vec1,
- &vector_Type, &vec2,
- &vector_Type, &vec3))
- {
- return NULL;
- }
-
- if (vec1->size != vec2->size || vec1->size != vec3->size) {
- PyErr_SetString(PyExc_ValueError,
- "vectors must be of the same size");
- return NULL;
- }
- if (vec1->size < 3) {
- PyErr_SetString(PyExc_ValueError,
- "2D vectors unsupported");
- return NULL;
- }
-
- if (BaseMath_ReadCallback(vec1) == -1 ||
- BaseMath_ReadCallback(vec2) == -1 ||
- BaseMath_ReadCallback(vec3) == -1)
- {
- return NULL;
- }
-
- normal_tri_v3(n, vec1->vec, vec2->vec, vec3->vec);
+ /* use */
+ if (PyTuple_GET_SIZE(args) == 1) {
+ args = PyTuple_GET_ITEM(args, 0);
}
- else {
- if (!PyArg_ParseTuple(args, "O!O!O!O!:normal",
- &vector_Type, &vec1,
- &vector_Type, &vec2,
- &vector_Type, &vec3,
- &vector_Type, &vec4))
- {
- return NULL;
- }
- if (vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
- PyErr_SetString(PyExc_ValueError,
- "vectors must be of the same size");
- return NULL;
- }
- if (vec1->size < 3) {
- PyErr_SetString(PyExc_ValueError,
- "2D vectors unsupported");
- return NULL;
- }
- if (BaseMath_ReadCallback(vec1) == -1 ||
- BaseMath_ReadCallback(vec2) == -1 ||
- BaseMath_ReadCallback(vec3) == -1 ||
- BaseMath_ReadCallback(vec4) == -1)
- {
- return NULL;
- }
+ if ((coords_len = mathutils_array_parse_alloc_v((float **)&coords, 3 | MU_ARRAY_SPILL, args, "normal")) == -1) {
+ return NULL;
+ }
- normal_quad_v3(n, vec1->vec, vec2->vec, vec3->vec, vec4->vec);
+ if (coords_len < 3) {
+ PyErr_SetString(PyExc_ValueError,
+ "Expected 3 or more vectors");
+ goto finally;
}
- return Vector_CreatePyObject(n, 3, Py_NEW, NULL);
+ normal_poly_v3(n, (const float (*)[3])coords, coords_len);
+ ret = Vector_CreatePyObject(n, 3, NULL);
+
+finally:
+ PyMem_Free(coords);
+ return ret;
}
/* --------------------------------- AREA FUNCTIONS-------------------- */
@@ -438,40 +348,26 @@ PyDoc_STRVAR(M_Geometry_area_tri_doc,
);
static PyObject *M_Geometry_area_tri(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *vec1, *vec2, *vec3;
-
- if (!PyArg_ParseTuple(args, "O!O!O!:area_tri",
- &vector_Type, &vec1,
- &vector_Type, &vec2,
- &vector_Type, &vec3))
+ const char *error_prefix = "area_tri";
+ PyObject *py_tri[3];
+ float tri[3][3];
+ int len;
+
+ if (!PyArg_ParseTuple(
+ args, "OOO:area_tri",
+ UNPACK3_EX(&, py_tri, )))
{
return NULL;
}
- if (vec1->size != vec2->size || vec1->size != vec3->size) {
- PyErr_SetString(PyExc_ValueError,
- "vectors must be of the same size");
- return NULL;
- }
-
- if (BaseMath_ReadCallback(vec1) == -1 ||
- BaseMath_ReadCallback(vec2) == -1 ||
- BaseMath_ReadCallback(vec3) == -1)
+ if ((((len = mathutils_array_parse(tri[0], 2, 3, py_tri[0], error_prefix)) != -1) &&
+ (mathutils_array_parse(tri[1], len, len, py_tri[1], error_prefix) != -1) &&
+ (mathutils_array_parse(tri[2], len, len, py_tri[2], error_prefix) != -1)) == 0)
{
return NULL;
}
- if (vec1->size == 3) {
- return PyFloat_FromDouble(area_tri_v3(vec1->vec, vec2->vec, vec3->vec));
- }
- else if (vec1->size == 2) {
- return PyFloat_FromDouble(area_tri_v2(vec1->vec, vec2->vec, vec3->vec));
- }
- else {
- PyErr_SetString(PyExc_ValueError,
- "only 2D,3D vectors are supported");
- return NULL;
- }
+ return PyFloat_FromDouble((len == 3 ? area_tri_v3 : area_tri_v2)(UNPACK3(tri)));
}
PyDoc_STRVAR(M_Geometry_volume_tetrahedron_doc,
@@ -491,33 +387,25 @@ PyDoc_STRVAR(M_Geometry_volume_tetrahedron_doc,
);
static PyObject *M_Geometry_volume_tetrahedron(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *vec1, *vec2, *vec3, *vec4;
+ const char *error_prefix = "volume_tetrahedron";
+ PyObject *py_tet[4];
+ float tet[4][3];
+ int i;
- if (!PyArg_ParseTuple(args, "O!O!O!O!:volume_tetrahedron",
- &vector_Type, &vec1,
- &vector_Type, &vec2,
- &vector_Type, &vec3,
- &vector_Type, &vec4))
+ if (!PyArg_ParseTuple(
+ args, "OOOO:volume_tetrahedron",
+ UNPACK4_EX(&, py_tet, )))
{
return NULL;
}
- if (vec1->size < 3 || vec2->size < 3 || vec3->size < 3 || vec4->size < 3) {
- PyErr_SetString(PyExc_ValueError,
- "geometry.volume_tetrahedron(...): "
- " can't use 2D Vectors");
- return NULL;
- }
-
- if (BaseMath_ReadCallback(vec1) == -1 ||
- BaseMath_ReadCallback(vec2) == -1 ||
- BaseMath_ReadCallback(vec3) == -1 ||
- BaseMath_ReadCallback(vec4) == -1)
- {
- return NULL;
+ for (i = 0; i < ARRAY_SIZE(tet); i++) {
+ if (mathutils_array_parse(tet[i], 3, 3 | MU_ARRAY_SPILL, py_tet[i], error_prefix) == -1) {
+ return NULL;
+ }
}
- return PyFloat_FromDouble(volume_tetrahedron_v3(vec1->vec, vec2->vec, vec3->vec, vec4->vec));
+ return PyFloat_FromDouble(volume_tetrahedron_v3(UNPACK4(tet)));
}
PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc,
@@ -538,27 +426,27 @@ PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc,
);
static PyObject *M_Geometry_intersect_line_line_2d(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
+ const char *error_prefix = "intersect_line_line_2d";
+ PyObject *py_lines[4];
+ float lines[4][2];
float vi[2];
- if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line_2d",
- &vector_Type, &line_a1,
- &vector_Type, &line_a2,
- &vector_Type, &line_b1,
- &vector_Type, &line_b2))
+ int i;
+
+ if (!PyArg_ParseTuple(
+ args, "OOOO:intersect_line_line_2d",
+ UNPACK4_EX(&, py_lines, )))
{
return NULL;
}
-
- if (BaseMath_ReadCallback(line_a1) == -1 ||
- BaseMath_ReadCallback(line_a2) == -1 ||
- BaseMath_ReadCallback(line_b1) == -1 ||
- BaseMath_ReadCallback(line_b2) == -1)
- {
- return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(lines); i++) {
+ if (mathutils_array_parse(lines[i], 2, 2 | MU_ARRAY_SPILL, py_lines[i], error_prefix) == -1) {
+ return NULL;
+ }
}
- if (isect_seg_seg_v2_point(line_a1->vec, line_a2->vec, line_b1->vec, line_b2->vec, vi) == 1) {
- return Vector_CreatePyObject(vi, 2, Py_NEW, NULL);
+ if (isect_seg_seg_v2_point(UNPACK4(lines), vi) == 1) {
+ return Vector_CreatePyObject(vi, 2, NULL);
}
else {
Py_RETURN_NONE;
@@ -585,38 +473,31 @@ PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc,
);
static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *line_a, *line_b, *plane_co, *plane_no;
+ const char *error_prefix = "intersect_line_plane";
+ PyObject *py_line_a, *py_line_b, *py_plane_co, *py_plane_no;
+ float line_a[3], line_b[3], plane_co[3], plane_no[3];
float isect[3];
int no_flip = false;
- if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_line_plane",
- &vector_Type, &line_a,
- &vector_Type, &line_b,
- &vector_Type, &plane_co,
- &vector_Type, &plane_no,
- &no_flip))
+ if (!PyArg_ParseTuple(
+ args, "OOOO|i:intersect_line_plane",
+ &py_line_a, &py_line_b, &py_plane_co, &py_plane_no,
+ &no_flip))
{
return NULL;
}
- if (BaseMath_ReadCallback(line_a) == -1 ||
- BaseMath_ReadCallback(line_b) == -1 ||
- BaseMath_ReadCallback(plane_co) == -1 ||
- BaseMath_ReadCallback(plane_no) == -1)
+ if (((mathutils_array_parse(line_a, 3, 3 | MU_ARRAY_SPILL, py_line_a, error_prefix) != -1) &&
+ (mathutils_array_parse(line_b, 3, 3 | MU_ARRAY_SPILL, py_line_b, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_co, 3, 3 | MU_ARRAY_SPILL, py_plane_co, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_no, 3, 3 | MU_ARRAY_SPILL, py_plane_no, error_prefix) != -1)) == 0)
{
return NULL;
}
- if (ELEM(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) {
- PyErr_SetString(PyExc_ValueError,
- "geometry.intersect_line_plane(...): "
- " can't use 2D Vectors");
- return NULL;
- }
-
/* TODO: implements no_flip */
- if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec) == 1) {
- return Vector_CreatePyObject(isect, 3, Py_NEW, NULL);
+ if (isect_line_plane_v3(isect, line_a, line_b, plane_co, plane_no) == 1) {
+ return Vector_CreatePyObject(isect, 3, NULL);
}
else {
Py_RETURN_NONE;
@@ -641,68 +522,59 @@ PyDoc_STRVAR(M_Geometry_intersect_plane_plane_doc,
);
static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObject *args)
{
+ const char *error_prefix = "intersect_plane_plane";
PyObject *ret, *ret_co, *ret_no;
- VectorObject *plane_a_co, *plane_a_no, *plane_b_co, *plane_b_no;
+ PyObject *py_plane_a_co, *py_plane_a_no, *py_plane_b_co, *py_plane_b_no;
+ float plane_a_co[3], plane_a_no[3], plane_b_co[3], plane_b_no[3];
float isect_co[3];
float isect_no[3];
- if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_plane_plane",
- &vector_Type, &plane_a_co,
- &vector_Type, &plane_a_no,
- &vector_Type, &plane_b_co,
- &vector_Type, &plane_b_no))
+ if (!PyArg_ParseTuple(
+ args, "OOOO:intersect_plane_plane",
+ &py_plane_a_co, &py_plane_a_no, &py_plane_b_co, &py_plane_b_no))
{
return NULL;
}
- if (BaseMath_ReadCallback(plane_a_co) == -1 ||
- BaseMath_ReadCallback(plane_a_no) == -1 ||
- BaseMath_ReadCallback(plane_b_co) == -1 ||
- BaseMath_ReadCallback(plane_b_no) == -1)
+ if (((mathutils_array_parse(plane_a_co, 3, 3 | MU_ARRAY_SPILL, py_plane_a_co, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_a_no, 3, 3 | MU_ARRAY_SPILL, py_plane_a_no, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_b_co, 3, 3 | MU_ARRAY_SPILL, py_plane_b_co, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_b_no, 3, 3 | MU_ARRAY_SPILL, py_plane_b_no, error_prefix) != -1)) == 0)
{
return NULL;
}
- if (ELEM(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) {
- PyErr_SetString(PyExc_ValueError,
- "geometry.intersect_plane_plane(...): "
- " can't use 2D Vectors");
- return NULL;
- }
-
if (isect_plane_plane_v3(isect_co, isect_no,
- plane_a_co->vec, plane_a_no->vec,
- plane_b_co->vec, plane_b_no->vec))
+ plane_a_co, plane_a_no,
+ plane_b_co, plane_b_no))
{
normalize_v3(isect_no);
- ret_co = Vector_CreatePyObject(isect_co, 3, Py_NEW, NULL);
- ret_no = Vector_CreatePyObject(isect_no, 3, Py_NEW, NULL);
+ ret_co = Vector_CreatePyObject(isect_co, 3, NULL);
+ ret_no = Vector_CreatePyObject(isect_no, 3, NULL);
}
else {
- ret_co = Py_None;
- ret_no = Py_None;
-
- Py_INCREF(ret_co);
- Py_INCREF(ret_no);
+ ret_co = Py_INCREF_RET(Py_None);
+ ret_no = Py_INCREF_RET(Py_None);
}
ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, ret_co);
- PyTuple_SET_ITEM(ret, 1, ret_no);
+ PyTuple_SET_ITEMS(ret,
+ ret_co,
+ ret_no);
return ret;
}
PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc,
".. function:: intersect_line_sphere(line_a, line_b, sphere_co, sphere_radius, clip=True)\n"
"\n"
-" Takes a lines (as 2 vectors), a sphere as a point and a radius and\n"
+" Takes a line (as 2 points) and a sphere (as a point and a radius) and\n"
" returns the intersection\n"
"\n"
-" :arg line_a: First point of the first line\n"
+" :arg line_a: First point of the line\n"
" :type line_a: :class:`mathutils.Vector`\n"
-" :arg line_b: Second point of the first line\n"
+" :arg line_b: Second point of the line\n"
" :type line_b: :class:`mathutils.Vector`\n"
" :arg sphere_co: The center of the sphere\n"
" :type sphere_co: :class:`mathutils.Vector`\n"
@@ -713,35 +585,28 @@ PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc,
);
static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *line_a, *line_b, *sphere_co;
+ const char *error_prefix = "intersect_line_sphere";
+ PyObject *py_line_a, *py_line_b, *py_sphere_co;
+ float line_a[3], line_b[3], sphere_co[3];
float sphere_radius;
int clip = true;
float isect_a[3];
float isect_b[3];
- if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere",
- &vector_Type, &line_a,
- &vector_Type, &line_b,
- &vector_Type, &sphere_co,
- &sphere_radius, &clip))
+ if (!PyArg_ParseTuple(
+ args, "OOOf|i:intersect_line_sphere",
+ &py_line_a, &py_line_b, &py_sphere_co, &sphere_radius, &clip))
{
return NULL;
}
- if (BaseMath_ReadCallback(line_a) == -1 ||
- BaseMath_ReadCallback(line_b) == -1 ||
- BaseMath_ReadCallback(sphere_co) == -1)
+ if (((mathutils_array_parse(line_a, 3, 3 | MU_ARRAY_SPILL, py_line_a, error_prefix) != -1) &&
+ (mathutils_array_parse(line_b, 3, 3 | MU_ARRAY_SPILL, py_line_b, error_prefix) != -1) &&
+ (mathutils_array_parse(sphere_co, 3, 3 | MU_ARRAY_SPILL, py_sphere_co, error_prefix) != -1)) == 0)
{
return NULL;
}
-
- if (ELEM(2, line_a->size, line_b->size, sphere_co->size)) {
- PyErr_SetString(PyExc_ValueError,
- "geometry.intersect_line_sphere(...): "
- " can't use 2D Vectors");
- return NULL;
- }
else {
bool use_a = true;
bool use_b = true;
@@ -749,14 +614,14 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje
PyObject *ret = PyTuple_New(2);
- switch (isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) {
+ switch (isect_line_sphere_v3(line_a, line_b, sphere_co, sphere_radius, isect_a, isect_b)) {
case 1:
- if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
+ if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
use_b = false;
break;
case 2:
- if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
- if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false;
+ if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
+ if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false;
break;
default:
use_a = false;
@@ -764,11 +629,9 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje
break;
}
- if (use_a) { PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_a, 3, Py_NEW, NULL)); }
- else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); }
-
- if (use_b) { PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_b, 3, Py_NEW, NULL)); }
- else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); }
+ PyTuple_SET_ITEMS(ret,
+ use_a ? Vector_CreatePyObject(isect_a, 3, NULL) : Py_INCREF_RET(Py_None),
+ use_b ? Vector_CreatePyObject(isect_b, 3, NULL) : Py_INCREF_RET(Py_None));
return ret;
}
@@ -778,12 +641,12 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje
PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc,
".. function:: intersect_line_sphere_2d(line_a, line_b, sphere_co, sphere_radius, clip=True)\n"
"\n"
-" Takes a lines (as 2 vectors), a sphere as a point and a radius and\n"
+" Takes a line (as 2 points) and a sphere (as a point and a radius) and\n"
" returns the intersection\n"
"\n"
-" :arg line_a: First point of the first line\n"
+" :arg line_a: First point of the line\n"
" :type line_a: :class:`mathutils.Vector`\n"
-" :arg line_b: Second point of the first line\n"
+" :arg line_b: Second point of the line\n"
" :type line_b: :class:`mathutils.Vector`\n"
" :arg sphere_co: The center of the sphere\n"
" :type sphere_co: :class:`mathutils.Vector`\n"
@@ -794,25 +657,25 @@ PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc,
);
static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *line_a, *line_b, *sphere_co;
+ const char *error_prefix = "intersect_line_sphere_2d";
+ PyObject *py_line_a, *py_line_b, *py_sphere_co;
+ float line_a[2], line_b[2], sphere_co[2];
float sphere_radius;
int clip = true;
float isect_a[2];
float isect_b[2];
- if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere_2d",
- &vector_Type, &line_a,
- &vector_Type, &line_b,
- &vector_Type, &sphere_co,
- &sphere_radius, &clip))
+ if (!PyArg_ParseTuple(
+ args, "OOOf|i:intersect_line_sphere_2d",
+ &py_line_a, &py_line_b, &py_sphere_co, &sphere_radius, &clip))
{
return NULL;
}
- if (BaseMath_ReadCallback(line_a) == -1 ||
- BaseMath_ReadCallback(line_b) == -1 ||
- BaseMath_ReadCallback(sphere_co) == -1)
+ if (((mathutils_array_parse(line_a, 2, 2 | MU_ARRAY_SPILL, py_line_a, error_prefix) != -1) &&
+ (mathutils_array_parse(line_b, 2, 2 | MU_ARRAY_SPILL, py_line_b, error_prefix) != -1) &&
+ (mathutils_array_parse(sphere_co, 2, 2 | MU_ARRAY_SPILL, py_sphere_co, error_prefix) != -1)) == 0)
{
return NULL;
}
@@ -823,14 +686,14 @@ static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyO
PyObject *ret = PyTuple_New(2);
- switch (isect_line_sphere_v2(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) {
+ switch (isect_line_sphere_v2(line_a, line_b, sphere_co, sphere_radius, isect_a, isect_b)) {
case 1:
- if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
+ if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
use_b = false;
break;
case 2:
- if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
- if (!(!clip || (((lambda = line_point_factor_v2(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false;
+ if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false;
+ if (!(!clip || (((lambda = line_point_factor_v2(isect_b, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false;
break;
default:
use_a = false;
@@ -838,11 +701,9 @@ static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyO
break;
}
- if (use_a) { PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_a, 2, Py_NEW, NULL)); }
- else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); }
-
- if (use_b) { PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_b, 2, Py_NEW, NULL)); }
- else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); }
+ PyTuple_SET_ITEMS(ret,
+ use_a ? Vector_CreatePyObject(isect_a, 2, NULL) : Py_INCREF_RET(Py_None),
+ use_b ? Vector_CreatePyObject(isect_b, 2, NULL) : Py_INCREF_RET(Py_None));
return ret;
}
@@ -863,43 +724,35 @@ PyDoc_STRVAR(M_Geometry_intersect_point_line_doc,
);
static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *pt, *line_1, *line_2;
- float pt_in[3], pt_out[3], l1[3], l2[3];
+ const char *error_prefix = "intersect_point_line";
+ PyObject *py_pt, *py_line_a, *py_line_b;
+ float pt[3], pt_out[3], line_a[3], line_b[3];
float lambda;
PyObject *ret;
int size = 2;
- if (!PyArg_ParseTuple(args, "O!O!O!:intersect_point_line",
- &vector_Type, &pt,
- &vector_Type, &line_1,
- &vector_Type, &line_2))
+ if (!PyArg_ParseTuple(
+ args, "OOO:intersect_point_line",
+ &py_pt, &py_line_a, &py_line_b))
{
return NULL;
}
- if (BaseMath_ReadCallback(pt) == -1 ||
- BaseMath_ReadCallback(line_1) == -1 ||
- BaseMath_ReadCallback(line_2) == -1)
+ /* accept 2d verts */
+ if ((((size = mathutils_array_parse(pt, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_pt, error_prefix)) != -1) &&
+ (mathutils_array_parse(line_a, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_a, error_prefix) != -1) &&
+ (mathutils_array_parse(line_b, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_b, error_prefix) != -1)) == 0)
{
return NULL;
}
- /* accept 2d verts */
- if (pt->size >= 3) { copy_v3_v3(pt_in, pt->vec); size = 3; }
- else { copy_v2_v2(pt_in, pt->vec); pt_in[2] = 0.0f; }
-
- if (line_1->size >= 3) { copy_v3_v3(l1, line_1->vec); size = 3; }
- else { copy_v2_v2(l1, line_1->vec); l1[2] = 0.0f; }
-
- if (line_2->size >= 3) { copy_v3_v3(l2, line_2->vec); size = 3; }
- else { copy_v2_v2(l2, line_2->vec); l2[2] = 0.0f; }
-
/* do the calculation */
- lambda = closest_to_line_v3(pt_out, pt_in, l1, l2);
+ lambda = closest_to_line_v3(pt_out, pt, line_a, line_b);
ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(pt_out, size, Py_NEW, NULL));
- PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda));
+ PyTuple_SET_ITEMS(ret,
+ Vector_CreatePyObject(pt_out, size, NULL),
+ PyFloat_FromDouble(lambda));
return ret;
}
@@ -921,38 +774,30 @@ PyDoc_STRVAR(M_Geometry_intersect_point_tri_doc,
);
static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
+ const char *error_prefix = "intersect_point_tri";
+ PyObject *py_pt, *py_tri[3];
+ float pt[3], tri[3][3];
float vi[3];
+ int i;
- if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri",
- &vector_Type, &pt_vec,
- &vector_Type, &tri_p1,
- &vector_Type, &tri_p2,
- &vector_Type, &tri_p3))
+ if (!PyArg_ParseTuple(
+ args, "OOOO:intersect_point_tri",
+ &py_pt, UNPACK3_EX(&, py_tri, )))
{
return NULL;
}
- if (BaseMath_ReadCallback(pt_vec) == -1 ||
- BaseMath_ReadCallback(tri_p1) == -1 ||
- BaseMath_ReadCallback(tri_p2) == -1 ||
- BaseMath_ReadCallback(tri_p3) == -1)
- {
+ if (mathutils_array_parse(pt, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_pt, error_prefix) == -1) {
return NULL;
}
-
- if (pt_vec->size < 3 ||
- tri_p1->size < 3 ||
- tri_p2->size < 3 ||
- tri_p3->size < 3)
- {
- PyErr_SetString(PyExc_ValueError,
- "One of more of the vector arguments wasn't a 3D vector");
- return NULL;
+ for (i = 0; i < ARRAY_SIZE(tri); i++) {
+ if (mathutils_array_parse(tri[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_tri[i], error_prefix) == -1) {
+ return NULL;
+ }
}
- if (isect_point_tri_v3(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec, vi)) {
- return Vector_CreatePyObject(vi, 3, Py_NEW, NULL);
+ if (isect_point_tri_v3(pt, UNPACK3(tri), vi)) {
+ return Vector_CreatePyObject(vi, 3, NULL);
}
else {
Py_RETURN_NONE;
@@ -976,26 +821,28 @@ PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc,
);
static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
-
- if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d",
- &vector_Type, &pt_vec,
- &vector_Type, &tri_p1,
- &vector_Type, &tri_p2,
- &vector_Type, &tri_p3))
+ const char *error_prefix = "intersect_point_tri_2d";
+ PyObject *py_pt, *py_tri[3];
+ float pt[2], tri[3][2];
+ int i;
+
+ if (!PyArg_ParseTuple(
+ args, "OOOO:intersect_point_tri_2d",
+ &py_pt, UNPACK3_EX(&, py_tri, )))
{
return NULL;
}
-
- if (BaseMath_ReadCallback(pt_vec) == -1 ||
- BaseMath_ReadCallback(tri_p1) == -1 ||
- BaseMath_ReadCallback(tri_p2) == -1 ||
- BaseMath_ReadCallback(tri_p3) == -1)
- {
+
+ if (mathutils_array_parse(pt, 2, 2 | MU_ARRAY_SPILL, py_pt, error_prefix) == -1) {
return NULL;
}
+ for (i = 0; i < ARRAY_SIZE(tri); i++) {
+ if (mathutils_array_parse(tri[i], 2, 2 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) {
+ return NULL;
+ }
+ }
- return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
+ return PyLong_FromLong(isect_point_tri_v2(pt, UNPACK3(tri)));
}
PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc,
@@ -1019,28 +866,28 @@ PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc,
);
static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4;
+ const char *error_prefix = "intersect_point_quad_2d";
+ PyObject *py_pt, *py_quad[4];
+ float pt[2], quad[4][2];
+ int i;
- if (!PyArg_ParseTuple(args, "O!O!O!O!O!:intersect_point_quad_2d",
- &vector_Type, &pt_vec,
- &vector_Type, &quad_p1,
- &vector_Type, &quad_p2,
- &vector_Type, &quad_p3,
- &vector_Type, &quad_p4))
+ if (!PyArg_ParseTuple(
+ args, "OOOOO:intersect_point_quad_2d",
+ &py_pt, UNPACK4_EX(&, py_quad, )))
{
return NULL;
}
- if (BaseMath_ReadCallback(pt_vec) == -1 ||
- BaseMath_ReadCallback(quad_p1) == -1 ||
- BaseMath_ReadCallback(quad_p2) == -1 ||
- BaseMath_ReadCallback(quad_p3) == -1 ||
- BaseMath_ReadCallback(quad_p4) == -1)
- {
+ if (mathutils_array_parse(pt, 2, 2 | MU_ARRAY_SPILL, py_pt, error_prefix) == -1) {
return NULL;
}
+ for (i = 0; i < ARRAY_SIZE(quad); i++) {
+ if (mathutils_array_parse(quad[i], 2, 2 | MU_ARRAY_SPILL, py_quad[i], error_prefix) == -1) {
+ return NULL;
+ }
+ }
- return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec));
+ return PyLong_FromLong(isect_point_quad_v2(pt, UNPACK4(quad)));
}
PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc,
@@ -1059,35 +906,27 @@ PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc,
);
static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *pt, *plane_co, *plane_no;
+ const char *error_prefix = "distance_point_to_plane";
+ PyObject *py_pt, *py_plane_co, *py_plane_no;
+ float pt[3], plane_co[3], plane_no[3];
float plane[4];
- if (!PyArg_ParseTuple(args, "O!O!O!:distance_point_to_plane",
- &vector_Type, &pt,
- &vector_Type, &plane_co,
- &vector_Type, &plane_no))
- {
- return NULL;
- }
-
- if (pt->size != 3 ||
- plane_co->size != 3 ||
- plane_no->size != 3)
+ if (!PyArg_ParseTuple(
+ args, "OOO:distance_point_to_plane",
+ &py_pt, &py_plane_co, &py_plane_no))
{
- PyErr_SetString(PyExc_ValueError,
- "One of more of the vector arguments wasn't a 3D vector");
return NULL;
}
- if (BaseMath_ReadCallback(pt) == -1 ||
- BaseMath_ReadCallback(plane_co) == -1 ||
- BaseMath_ReadCallback(plane_no) == -1)
+ if (((mathutils_array_parse(pt, 3, 3 | MU_ARRAY_SPILL, py_pt, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_co, 3, 3 | MU_ARRAY_SPILL, py_plane_co, error_prefix) != -1) &&
+ (mathutils_array_parse(plane_no, 3, 3 | MU_ARRAY_SPILL, py_plane_no, error_prefix) != -1)) == 0)
{
return NULL;
}
- plane_from_point_normal_v3(plane, plane_co->vec, plane_no->vec);
- return PyFloat_FromDouble(dist_signed_to_plane_v3(pt->vec, plane));
+ plane_from_point_normal_v3(plane, plane_co, plane_no);
+ return PyFloat_FromDouble(dist_signed_to_plane_v3(pt, plane));
}
PyDoc_STRVAR(M_Geometry_barycentric_transform_doc,
@@ -1114,53 +953,37 @@ PyDoc_STRVAR(M_Geometry_barycentric_transform_doc,
);
static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *vec_pt;
- VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar;
- VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src;
- float vec[3];
-
- if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!::barycentric_transform",
- &vector_Type, &vec_pt,
- &vector_Type, &vec_t1_src,
- &vector_Type, &vec_t2_src,
- &vector_Type, &vec_t3_src,
- &vector_Type, &vec_t1_tar,
- &vector_Type, &vec_t2_tar,
- &vector_Type, &vec_t3_tar))
- {
- return NULL;
- }
+ const char *error_prefix = "barycentric_transform";
+ PyObject *py_pt_src, *py_tri_src[3], *py_tri_dst[3];
+ float pt_src[3], pt_dst[3], tri_src[3][3], tri_dst[3][3];
+ int i;
- if (vec_pt->size != 3 ||
- vec_t1_src->size != 3 ||
- vec_t2_src->size != 3 ||
- vec_t3_src->size != 3 ||
- vec_t1_tar->size != 3 ||
- vec_t2_tar->size != 3 ||
- vec_t3_tar->size != 3)
+ if (!PyArg_ParseTuple(
+ args, "OOOOOOO:barycentric_transform",
+ &py_pt_src,
+ UNPACK3_EX(&, py_tri_src, ),
+ UNPACK3_EX(&, py_tri_dst, )))
{
- PyErr_SetString(PyExc_ValueError,
- "One of more of the vector arguments wasn't a 3D vector");
return NULL;
}
- if (BaseMath_ReadCallback(vec_pt) == -1 ||
- BaseMath_ReadCallback(vec_t1_src) == -1 ||
- BaseMath_ReadCallback(vec_t2_src) == -1 ||
- BaseMath_ReadCallback(vec_t3_src) == -1 ||
- BaseMath_ReadCallback(vec_t1_tar) == -1 ||
- BaseMath_ReadCallback(vec_t2_tar) == -1 ||
- BaseMath_ReadCallback(vec_t3_tar) == -1)
- {
+ if (mathutils_array_parse(pt_src, 3, 3 | MU_ARRAY_SPILL, py_pt_src, error_prefix) == -1) {
return NULL;
}
+ for (i = 0; i < ARRAY_SIZE(tri_src); i++) {
+ if (((mathutils_array_parse(tri_src[i], 3, 3 | MU_ARRAY_SPILL, py_tri_src[i], error_prefix) != -1) &&
+ (mathutils_array_parse(tri_dst[i], 3, 3 | MU_ARRAY_SPILL, py_tri_dst[i], error_prefix) != -1)) == 0)
+ {
+ return NULL;
+ }
+ }
transform_point_by_tri_v3(
- vec, vec_pt->vec,
- vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec,
- vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec);
+ pt_dst, pt_src,
+ UNPACK3(tri_dst),
+ UNPACK3(tri_src));
- return Vector_CreatePyObject(vec, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(pt_dst, 3, NULL);
}
PyDoc_STRVAR(M_Geometry_points_in_planes_doc,
@@ -1180,8 +1003,9 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a
float (*planes)[4];
unsigned int planes_len;
- if (!PyArg_ParseTuple(args, "O:points_in_planes",
- &py_planes))
+ if (!PyArg_ParseTuple(
+ args, "O:points_in_planes",
+ &py_planes))
{
return NULL;
}
@@ -1233,10 +1057,7 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a
if (l == len) { /* ok */
/* python */
- PyObject *item = Vector_CreatePyObject(potentialVertex, 3, Py_NEW, NULL);
- PyList_Append(py_verts, item);
- Py_DECREF(item);
-
+ PyList_APPEND(py_verts, Vector_CreatePyObject(potentialVertex, 3, NULL));
planes_used[i] = planes_used[j] = planes_used[k] = true;
}
}
@@ -1252,17 +1073,16 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a
/* now make a list of used planes */
for (i = 0; i < len; i++) {
if (planes_used[i]) {
- PyObject *item = PyLong_FromLong(i);
- PyList_Append(py_plane_index, item);
- Py_DECREF(item);
+ PyList_APPEND(py_plane_index, PyLong_FromLong(i));
}
}
PyMem_Free(planes_used);
{
PyObject *ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, py_verts);
- PyTuple_SET_ITEM(ret, 1, py_plane_index);
+ PyTuple_SET_ITEMS(ret,
+ py_verts,
+ py_plane_index);
return ret;
}
}
@@ -1290,58 +1110,45 @@ PyDoc_STRVAR(M_Geometry_interpolate_bezier_doc,
);
static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject *args)
{
- VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2;
+ const char *error_prefix = "interpolate_bezier";
+ PyObject *py_data[4];
+ float data[4][4] = {{0.0f}};
int resolu;
- int dims;
+ int dims = 0;
int i;
float *coord_array, *fp;
PyObject *list;
- float k1[4] = {0.0, 0.0, 0.0, 0.0};
- float h1[4] = {0.0, 0.0, 0.0, 0.0};
- float k2[4] = {0.0, 0.0, 0.0, 0.0};
- float h2[4] = {0.0, 0.0, 0.0, 0.0};
-
-
- if (!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier",
- &vector_Type, &vec_k1,
- &vector_Type, &vec_h1,
- &vector_Type, &vec_h2,
- &vector_Type, &vec_k2, &resolu))
+ if (!PyArg_ParseTuple(
+ args, "OOOOi:interpolate_bezier",
+ UNPACK4_EX(&, py_data, ), &resolu))
{
return NULL;
}
+ for (i = 0; i < 4; i++) {
+ int dims_tmp;
+ if ((dims_tmp = mathutils_array_parse(data[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_data[i], error_prefix)) == -1) {
+ return NULL;
+ }
+ dims = max_ii(dims, dims_tmp);
+ }
+
if (resolu <= 1) {
PyErr_SetString(PyExc_ValueError,
"resolution must be 2 or over");
return NULL;
}
- if (BaseMath_ReadCallback(vec_k1) == -1 ||
- BaseMath_ReadCallback(vec_h1) == -1 ||
- BaseMath_ReadCallback(vec_k2) == -1 ||
- BaseMath_ReadCallback(vec_h2) == -1)
- {
- return NULL;
- }
-
- dims = max_iiii(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size);
-
- for (i = 0; i < vec_k1->size; i++) k1[i] = vec_k1->vec[i];
- for (i = 0; i < vec_h1->size; i++) h1[i] = vec_h1->vec[i];
- for (i = 0; i < vec_k2->size; i++) k2[i] = vec_k2->vec[i];
- for (i = 0; i < vec_h2->size; i++) h2[i] = vec_h2->vec[i];
-
- coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier");
+ coord_array = MEM_callocN(dims * (resolu) * sizeof(float), error_prefix);
for (i = 0; i < dims; i++) {
- BKE_curve_forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float) * dims);
+ BKE_curve_forward_diff_bezier(UNPACK4_EX(, data, [i]), coord_array + i, resolu - 1, sizeof(float) * dims);
}
list = PyList_New(resolu);
fp = coord_array;
for (i = 0; i < resolu; i++, fp = fp + dims) {
- PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, Py_NEW, NULL));
+ PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, NULL));
}
MEM_freeN(coord_array);
return list;
@@ -1581,8 +1388,9 @@ static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlis
}
ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(tot_width));
- PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(tot_height));
+ PyTuple_SET_ITEMS(ret,
+ PyFloat_FromDouble(tot_width),
+ PyFloat_FromDouble(tot_height));
return ret;
}
diff --git a/source/blender/python/mathutils/mathutils_interpolate.c b/source/blender/python/mathutils/mathutils_interpolate.c
new file mode 100644
index 00000000000..4d7841b906a
--- /dev/null
+++ b/source/blender/python/mathutils/mathutils_interpolate.c
@@ -0,0 +1,137 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/mathutils/mathutils_interpolate.c
+ * \ingroup pymathutils
+ */
+
+
+#include <Python.h>
+
+#include "mathutils.h"
+#include "mathutils_interpolate.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#ifndef MATH_STANDALONE /* define when building outside blender */
+# include "MEM_guardedalloc.h"
+#endif
+
+/*-------------------------DOC STRINGS ---------------------------*/
+PyDoc_STRVAR(M_Interpolate_doc,
+"The Blender interpolate module"
+);
+
+/* ---------------------------------WEIGHT CALCULATION ----------------------- */
+
+#ifndef MATH_STANDALONE
+
+PyDoc_STRVAR(M_Interpolate_poly_3d_calc_doc,
+".. function:: poly_3d_calc(veclist, pt)\n"
+"\n"
+" Calculate barycentric weights for a point on a polygon.\n"
+"\n"
+" :arg veclist: list of vectors\n"
+" :arg pt: point"
+" :rtype: list of per-vector weights\n"
+);
+static PyObject *M_Interpolate_poly_3d_calc(PyObject *UNUSED(self), PyObject *args)
+{
+ float fp[3];
+ float (*vecs)[3];
+ Py_ssize_t len;
+
+ PyObject *point, *veclist, *ret;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "OO!:interpolation_weights",
+ &veclist,
+ &vector_Type, &point))
+ {
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback((VectorObject *)point) == -1)
+ return NULL;
+
+ fp[0] = ((VectorObject *)point)->vec[0];
+ fp[1] = ((VectorObject *)point)->vec[1];
+ if (((VectorObject *)point)->size > 2)
+ fp[2] = ((VectorObject *)point)->vec[2];
+ else
+ fp[2] = 0.0f; /* if its a 2d vector then set the z to be zero */
+
+ len = mathutils_array_parse_alloc_v(((float **)&vecs), 3, veclist, "interpolation_weights");
+ if (len == -1) {
+ return NULL;
+ }
+
+ if (len) {
+ float *weights = MEM_mallocN(sizeof(float) * len, "interpolation weights");
+
+ interp_weights_poly_v3(weights, vecs, len, fp);
+
+ ret = PyList_New(len);
+ for (i = 0; i < len; i++) {
+ PyList_SET_ITEM(ret, i, PyFloat_FromDouble(weights[i]));
+ }
+
+ MEM_freeN(weights);
+
+ PyMem_Free(vecs);
+ }
+ else {
+ ret = PyList_New(0);
+ }
+
+ return ret;
+}
+
+#endif /* MATH_STANDALONE */
+
+
+static PyMethodDef M_Interpolate_methods[] = {
+#ifndef MATH_STANDALONE
+ {"poly_3d_calc", (PyCFunction) M_Interpolate_poly_3d_calc, METH_VARARGS, M_Interpolate_poly_3d_calc_doc},
+#endif
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef M_Interpolate_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "mathutils.interpolate", /* m_name */
+ M_Interpolate_doc, /* m_doc */
+ 0, /* m_size */
+ M_Interpolate_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+/*----------------------------MODULE INIT-------------------------*/
+PyMODINIT_FUNC PyInit_mathutils_interpolate(void)
+{
+ PyObject *submodule = PyModule_Create(&M_Interpolate_module_def);
+ return submodule;
+}
diff --git a/source/blender/python/mathutils/mathutils_interpolate.h b/source/blender/python/mathutils/mathutils_interpolate.h
new file mode 100644
index 00000000000..1bbff6f3286
--- /dev/null
+++ b/source/blender/python/mathutils/mathutils_interpolate.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __MATHUTILS_INTERPOLATE_H__
+#define __MATHUTILS_INTERPOLATE_H__
+
+/** \file blender/python/mathutils/mathutils_interpolate.h
+ * \ingroup pymathutils
+ */
+
+PyMODINIT_FUNC PyInit_mathutils_interpolate(void);
+
+#endif /* __MATHUTILS_INTERPOLATE_H__ */
diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c
index 519778aea7d..199c2e02da4 100644
--- a/source/blender/python/mathutils/mathutils_kdtree.c
+++ b/source/blender/python/mathutils/mathutils_kdtree.c
@@ -35,6 +35,7 @@
#include "BLI_kdtree.h"
#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
#include "mathutils.h"
#include "mathutils_kdtree.h" /* own include */
@@ -58,9 +59,10 @@ static void kdtree_nearest_to_py_tuple(const KDTreeNearest *nearest, PyObject *p
BLI_assert(nearest->index >= 0);
BLI_assert(PyTuple_GET_SIZE(py_retval) == 3);
- PyTuple_SET_ITEM(py_retval, 0, Vector_CreatePyObject((float *)nearest->co, 3, Py_NEW, NULL));
- PyTuple_SET_ITEM(py_retval, 1, PyLong_FromLong(nearest->index));
- PyTuple_SET_ITEM(py_retval, 2, PyFloat_FromDouble(nearest->dist));
+ PyTuple_SET_ITEMS(py_retval,
+ Vector_CreatePyObject((float *)nearest->co, 3, NULL),
+ PyLong_FromLong(nearest->index),
+ PyFloat_FromDouble(nearest->dist));
}
static PyObject *kdtree_nearest_to_py(const KDTreeNearest *nearest)
@@ -126,7 +128,7 @@ static void PyKDTree__tp_dealloc(PyKDTree *self)
}
PyDoc_STRVAR(py_kdtree_insert_doc,
-".. method:: insert(index, co)\n"
+".. method:: insert(co, index)\n"
"\n"
" Insert a point into the KDTree.\n"
"\n"
@@ -171,6 +173,10 @@ PyDoc_STRVAR(py_kdtree_balance_doc,
".. method:: balance()\n"
"\n"
" Balance the tree.\n"
+"\n"
+".. note::\n"
+"\n"
+" This builds the entire tree, avoid calling after each insertion.\n"
);
static PyObject *py_kdtree_balance(PyKDTree *self)
{
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index 8dfa7904300..f0449c23dcd 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -34,8 +34,6 @@
#include <Python.h>
-#include "structseq.h"
-
#include "BLI_math.h"
#include "BLI_noise.h"
#include "BLI_utildefines.h"
@@ -311,7 +309,7 @@ static PyObject *M_Noise_random_unit_vector(PyObject *UNUSED(self), PyObject *ar
norm = normalize_vn(vec, size);
}
- return Vector_CreatePyObject(vec, size, Py_NEW, NULL);
+ return Vector_CreatePyObject(vec, size, NULL);
}
/* This is dumb, most people will want a unit vector anyway, since this doesn't have uniform distribution over a sphere*/
#if 0
@@ -340,7 +338,7 @@ static PyObject *M_Noise_random_vector(PyObject *UNUSED(self), PyObject *args)
rand_vn(vec, size);
- return Vector_CreatePyObject(vec, size, Py_NEW, NULL);
+ return Vector_CreatePyObject(vec, size, NULL);
}
#endif
@@ -414,7 +412,7 @@ static PyObject *M_Noise_noise_vector(PyObject *UNUSED(self), PyObject *args)
noise_vector(vec[0], vec[1], vec[2], nb, r_vec);
- return Vector_CreatePyObject(r_vec, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(r_vec, 3, NULL);
}
PyDoc_STRVAR(M_Noise_turbulence_doc,
@@ -486,7 +484,7 @@ static PyObject *M_Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *arg
return NULL;
vTurb(vec[0], vec[1], vec[2], oct, hd, nb, as, fs, r_vec);
- return Vector_CreatePyObject(r_vec, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(r_vec, 3, NULL);
}
/* F. Kenton Musgrave's fractal functions */
@@ -738,7 +736,7 @@ static PyObject *M_Noise_voronoi(PyObject *UNUSED(self), PyObject *args)
voronoi(vec[0], vec[1], vec[2], da, pa, me, dtype);
for (i = 0; i < 4; i++) {
- PyList_SET_ITEM(list, i, Vector_CreatePyObject(pa + 3 * i, 3, Py_NEW, NULL));
+ PyList_SET_ITEM(list, i, Vector_CreatePyObject(pa + 3 * i, 3, NULL));
}
return Py_BuildValue("[[ffff]O]", da[0], da[1], da[2], da[3], list);
@@ -790,7 +788,7 @@ static PyObject *M_Noise_cell_vector(PyObject *UNUSED(self), PyObject *args)
return NULL;
cellNoiseV(vec[0], vec[1], vec[2], r_vec);
- return Vector_CreatePyObject(r_vec, 3, Py_NEW, NULL);
+ return Vector_CreatePyObject(r_vec, 3, NULL);
}
static PyMethodDef M_Noise_methods[] = {