Cleanup: use doxy sections for mathutils types
Also minor improvements & corrections to comments.
This commit is contained in:
@@ -22,8 +22,40 @@
|
||||
|
||||
#define COLOR_SIZE 3
|
||||
|
||||
/* ----------------------------------mathutils.Color() ------------------- */
|
||||
/* makes a new color for you to play with */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note #BaseMath_ReadCallback must be called beforehand.
|
||||
*/
|
||||
static PyObject *Color_to_tuple_ex(ColorObject *self, int ndigits)
|
||||
{
|
||||
PyObject *ret;
|
||||
int i;
|
||||
|
||||
ret = PyTuple_New(COLOR_SIZE);
|
||||
|
||||
if (ndigits >= 0) {
|
||||
for (i = 0; i < COLOR_SIZE; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < COLOR_SIZE; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: `__new__` / `mathutils.Color()`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
float col[3] = {0.0f, 0.0f, 0.0f};
|
||||
@@ -54,29 +86,11 @@ static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
return Color_CreatePyObject(col, type);
|
||||
}
|
||||
|
||||
/* -----------------------------METHODS---------------------------- */
|
||||
/** \} */
|
||||
|
||||
/* NOTE: BaseMath_ReadCallback must be called beforehand. */
|
||||
static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits)
|
||||
{
|
||||
PyObject *ret;
|
||||
int i;
|
||||
|
||||
ret = PyTuple_New(COLOR_SIZE);
|
||||
|
||||
if (ndigits >= 0) {
|
||||
for (i = 0; i < COLOR_SIZE; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < COLOR_SIZE; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Methods: Color Space Conversion
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc,
|
||||
".. function:: from_scene_linear_to_srgb()\n"
|
||||
@@ -190,7 +204,11 @@ static PyObject *Color_from_rec709_linear_to_scene_linear(ColorObject *self)
|
||||
return Color_CreatePyObject(col, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/* ---------------------------- Colorspace conversion -------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Methods: Color Copy/Deep-Copy
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Color_copy_doc,
|
||||
".. function:: copy()\n"
|
||||
@@ -218,8 +236,11 @@ static PyObject *Color_deepcopy(ColorObject *self, PyObject *args)
|
||||
return Color_copy(self);
|
||||
}
|
||||
|
||||
/* ----------------------------print object (internal)-------------- */
|
||||
/* print the object to screen */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: `__repr__` & `__str__`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Color_repr(ColorObject *self)
|
||||
{
|
||||
@@ -229,7 +250,7 @@ static PyObject *Color_repr(ColorObject *self)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tuple = Color_ToTupleExt(self, -1);
|
||||
tuple = Color_to_tuple_ex(self, -1);
|
||||
|
||||
ret = PyUnicode_FromFormat("Color(%R)", tuple);
|
||||
|
||||
@@ -255,8 +276,12 @@ static PyObject *Color_str(ColorObject *self)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------tp_richcmpr */
|
||||
/* returns -1 exception, 0 false, 1 true */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Rich Compare
|
||||
* \{ */
|
||||
|
||||
static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
@@ -295,6 +320,12 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
return Py_INCREF_RET(res);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Hash (`__hash__`)
|
||||
* \{ */
|
||||
|
||||
static Py_hash_t Color_hash(ColorObject *self)
|
||||
{
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
@@ -308,15 +339,19 @@ static Py_hash_t Color_hash(ColorObject *self)
|
||||
return mathutils_array_hash(self->col, COLOR_SIZE);
|
||||
}
|
||||
|
||||
/* ---------------------SEQUENCE PROTOCOLS------------------------ */
|
||||
/* ----------------------------len(object)------------------------ */
|
||||
/* sequence length */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Sequence & Mapping Protocols Implementation
|
||||
* \{ */
|
||||
|
||||
/** Sequence length: `len(object)`. */
|
||||
static int Color_len(ColorObject *UNUSED(self))
|
||||
{
|
||||
return COLOR_SIZE;
|
||||
}
|
||||
/* ----------------------------object[]--------------------------- */
|
||||
/* sequence accessor (get) */
|
||||
|
||||
/** Sequence accessor (get): `x = object[i]`. */
|
||||
static PyObject *Color_item(ColorObject *self, int i)
|
||||
{
|
||||
if (i < 0) {
|
||||
@@ -336,8 +371,8 @@ static PyObject *Color_item(ColorObject *self, int i)
|
||||
|
||||
return PyFloat_FromDouble(self->col[i]);
|
||||
}
|
||||
/* ----------------------------object[]------------------------- */
|
||||
/* sequence accessor (set) */
|
||||
|
||||
/** Sequence accessor (set): `object[i] = x`. */
|
||||
static int Color_ass_item(ColorObject *self, int i, PyObject *value)
|
||||
{
|
||||
float f;
|
||||
@@ -373,8 +408,8 @@ static int Color_ass_item(ColorObject *self, int i, PyObject *value)
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ----------------------------object[z:y]------------------------ */
|
||||
/* sequence slice (get) */
|
||||
|
||||
/** Sequence slice accessor (get): `x = object[i:j]`. */
|
||||
static PyObject *Color_slice(ColorObject *self, int begin, int end)
|
||||
{
|
||||
PyObject *tuple;
|
||||
@@ -398,8 +433,8 @@ static PyObject *Color_slice(ColorObject *self, int begin, int end)
|
||||
|
||||
return tuple;
|
||||
}
|
||||
/* ----------------------------object[z:y]------------------------ */
|
||||
/* sequence slice (set) */
|
||||
|
||||
/** Sequence slice accessor (set): `object[i:j] = x`. */
|
||||
static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
|
||||
{
|
||||
int i, size;
|
||||
@@ -436,6 +471,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (get): `x = object[...]`. */
|
||||
static PyObject *Color_subscript(ColorObject *self, PyObject *item)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -472,6 +508,7 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (set): `object[...] = x`. */
|
||||
static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -504,29 +541,13 @@ static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *valu
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -----------------PROTCOL DECLARATIONS-------------------------- */
|
||||
static PySequenceMethods Color_SeqMethods = {
|
||||
(lenfunc)Color_len, /* sq_length */
|
||||
(binaryfunc)NULL, /* sq_concat */
|
||||
(ssizeargfunc)NULL, /* sq_repeat */
|
||||
(ssizeargfunc)Color_item, /* sq_item */
|
||||
NULL, /* sq_slice, deprecated */
|
||||
(ssizeobjargproc)Color_ass_item, /* sq_ass_item */
|
||||
NULL, /* sq_ass_slice, deprecated */
|
||||
(objobjproc)NULL, /* sq_contains */
|
||||
(binaryfunc)NULL, /* sq_inplace_concat */
|
||||
(ssizeargfunc)NULL, /* sq_inplace_repeat */
|
||||
};
|
||||
/** \} */
|
||||
|
||||
static PyMappingMethods Color_AsMapping = {
|
||||
(lenfunc)Color_len,
|
||||
(binaryfunc)Color_subscript,
|
||||
(objobjargproc)Color_ass_subscript,
|
||||
};
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Numeric Protocol Implementation
|
||||
* \{ */
|
||||
|
||||
/* numeric */
|
||||
|
||||
/* addition: obj + obj */
|
||||
/** Addition: `object + object`. */
|
||||
static PyObject *Color_add(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color1 = NULL, *color2 = NULL;
|
||||
@@ -552,7 +573,7 @@ static PyObject *Color_add(PyObject *v1, PyObject *v2)
|
||||
return Color_CreatePyObject(col, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* addition in-place: obj += obj */
|
||||
/** Addition in-place: `object += object`. */
|
||||
static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color1 = NULL, *color2 = NULL;
|
||||
@@ -579,7 +600,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
|
||||
return v1;
|
||||
}
|
||||
|
||||
/* subtraction: obj - obj */
|
||||
/** Subtraction: `object - object`. */
|
||||
static PyObject *Color_sub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color1 = NULL, *color2 = NULL;
|
||||
@@ -605,7 +626,7 @@ static PyObject *Color_sub(PyObject *v1, PyObject *v2)
|
||||
return Color_CreatePyObject(col, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* subtraction in-place: obj -= obj */
|
||||
/** Subtraction in-place: `object -= object`. */
|
||||
static PyObject *Color_isub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color1 = NULL, *color2 = NULL;
|
||||
@@ -639,6 +660,7 @@ static PyObject *color_mul_float(ColorObject *color, const float scalar)
|
||||
return Color_CreatePyObject(tcol, Py_TYPE(color));
|
||||
}
|
||||
|
||||
/** Multiplication: `object * object`. */
|
||||
static PyObject *Color_mul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color1 = NULL, *color2 = NULL;
|
||||
@@ -683,6 +705,7 @@ static PyObject *Color_mul(PyObject *v1, PyObject *v2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Division: `object / object`. */
|
||||
static PyObject *Color_div(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color1 = NULL;
|
||||
@@ -716,7 +739,7 @@ static PyObject *Color_div(PyObject *v1, PyObject *v2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* multiplication in-place: obj *= obj */
|
||||
/** Multiplication in-place: `object *= object`. */
|
||||
static PyObject *Color_imul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color = (ColorObject *)v1;
|
||||
@@ -744,7 +767,7 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2)
|
||||
return v1;
|
||||
}
|
||||
|
||||
/* multiplication in-place: obj *= obj */
|
||||
/** Division in-place: `object *= object`. */
|
||||
static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
ColorObject *color = (ColorObject *)v1;
|
||||
@@ -777,8 +800,7 @@ static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
|
||||
return v1;
|
||||
}
|
||||
|
||||
/* -obj
|
||||
* returns the negative of this object */
|
||||
/** Negative (returns the negative of this object): `-object`. */
|
||||
static PyObject *Color_neg(ColorObject *self)
|
||||
{
|
||||
float tcol[COLOR_SIZE];
|
||||
@@ -791,6 +813,31 @@ static PyObject *Color_neg(ColorObject *self)
|
||||
return Color_CreatePyObject(tcol, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Protocol Declarations
|
||||
* \{ */
|
||||
|
||||
static PySequenceMethods Color_SeqMethods = {
|
||||
(lenfunc)Color_len, /*sq_length*/
|
||||
(binaryfunc)NULL, /*sq_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_repeat*/
|
||||
(ssizeargfunc)Color_item, /*sq_item*/
|
||||
NULL, /*sq_slice(DEPRECATED)*/
|
||||
(ssizeobjargproc)Color_ass_item, /*sq_ass_item*/
|
||||
NULL, /*sq_ass_slice(DEPRECATED)*/
|
||||
(objobjproc)NULL, /*sq_contains*/
|
||||
(binaryfunc)NULL, /*sq_inplace_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_inplace_repeat*/
|
||||
};
|
||||
|
||||
static PyMappingMethods Color_AsMapping = {
|
||||
(lenfunc)Color_len,
|
||||
(binaryfunc)Color_subscript,
|
||||
(objobjargproc)Color_ass_subscript,
|
||||
};
|
||||
|
||||
static PyNumberMethods Color_NumMethods = {
|
||||
(binaryfunc)Color_add, /*nb_add*/
|
||||
(binaryfunc)Color_sub, /*nb_subtract*/
|
||||
@@ -811,24 +858,31 @@ static PyNumberMethods Color_NumMethods = {
|
||||
NULL, /*nb_int*/
|
||||
NULL, /*nb_reserved*/
|
||||
NULL, /*nb_float*/
|
||||
Color_iadd, /* nb_inplace_add */
|
||||
Color_isub, /* nb_inplace_subtract */
|
||||
Color_imul, /* nb_inplace_multiply */
|
||||
NULL, /* nb_inplace_remainder */
|
||||
NULL, /* nb_inplace_power */
|
||||
NULL, /* nb_inplace_lshift */
|
||||
NULL, /* nb_inplace_rshift */
|
||||
NULL, /* nb_inplace_and */
|
||||
NULL, /* nb_inplace_xor */
|
||||
NULL, /* nb_inplace_or */
|
||||
NULL, /* nb_floor_divide */
|
||||
Color_div, /* nb_true_divide */
|
||||
NULL, /* nb_inplace_floor_divide */
|
||||
Color_idiv, /* nb_inplace_true_divide */
|
||||
NULL, /* nb_index */
|
||||
Color_iadd, /*nb_inplace_add*/
|
||||
Color_isub, /*nb_inplace_subtract*/
|
||||
Color_imul, /*nb_inplace_multiply*/
|
||||
NULL, /*nb_inplace_remainder*/
|
||||
NULL, /*nb_inplace_power*/
|
||||
NULL, /*nb_inplace_lshift*/
|
||||
NULL, /*nb_inplace_rshift*/
|
||||
NULL, /*nb_inplace_and*/
|
||||
NULL, /*nb_inplace_xor*/
|
||||
NULL, /*nb_inplace_or*/
|
||||
NULL, /*nb_floor_divide*/
|
||||
Color_div, /*nb_true_divide*/
|
||||
NULL, /*nb_inplace_floor_divide*/
|
||||
Color_idiv, /*nb_inplace_true_divide*/
|
||||
NULL, /*nb_index*/
|
||||
};
|
||||
|
||||
/* color channel, vector.r/g/b */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Get/Set Item Implementation
|
||||
* \{ */
|
||||
|
||||
/* Color channel (RGB): `color.r/g/b`. */
|
||||
|
||||
PyDoc_STRVAR(Color_channel_r_doc, "Red color channel.\n\n:type: float");
|
||||
PyDoc_STRVAR(Color_channel_g_doc, "Green color channel.\n\n:type: float");
|
||||
PyDoc_STRVAR(Color_channel_b_doc, "Blue color channel.\n\n:type: float");
|
||||
@@ -843,7 +897,8 @@ static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
|
||||
return Color_ass_item(self, POINTER_AS_INT(type), value);
|
||||
}
|
||||
|
||||
/* color channel (HSV), color.h/s/v */
|
||||
/* Color channel (HSV): `color.h/s/v`. */
|
||||
|
||||
PyDoc_STRVAR(Color_channel_hsv_h_doc, "HSV Hue component in [0, 1].\n\n:type: float");
|
||||
PyDoc_STRVAR(Color_channel_hsv_s_doc, "HSV Saturation component in [0, 1].\n\n:type: float");
|
||||
PyDoc_STRVAR(Color_channel_hsv_v_doc, "HSV Value component in [0, 1].\n\n:type: float");
|
||||
@@ -891,8 +946,8 @@ static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* color channel (HSV), color.h/s/v */
|
||||
PyDoc_STRVAR(Color_hsv_doc, "HSV Values in [0, 1].\n\n:type: float triplet");
|
||||
/** Color channel HSV (get): `x = color.hsv`. */
|
||||
static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
|
||||
{
|
||||
float hsv[3];
|
||||
@@ -910,6 +965,7 @@ static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Color channel HSV (set): `color.hsv = x`. */
|
||||
static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closure))
|
||||
{
|
||||
float hsv[3];
|
||||
@@ -932,9 +988,12 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python attributes get/set structure: */
|
||||
/*****************************************************************************/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Get/Set Item Definitions
|
||||
* \{ */
|
||||
|
||||
static PyGetSetDef Color_getseters[] = {
|
||||
{"r", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_r_doc, (void *)0},
|
||||
{"g", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_g_doc, (void *)1},
|
||||
@@ -977,7 +1036,12 @@ static PyGetSetDef Color_getseters[] = {
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* -----------------------METHOD DEFINITIONS ---------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Method Definitions
|
||||
* \{ */
|
||||
|
||||
static struct PyMethodDef Color_methods[] = {
|
||||
{"copy", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
|
||||
{"__copy__", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
|
||||
@@ -1022,7 +1086,12 @@ static struct PyMethodDef Color_methods[] = {
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
/* ------------------PY_OBECT DEFINITION-------------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: Python Object Definition
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
color_doc,
|
||||
".. class:: Color(rgb)\n"
|
||||
@@ -1087,6 +1156,12 @@ PyTypeObject color_Type = {
|
||||
NULL, /* tp_del */
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Color Type: C/API Constructors
|
||||
* \{ */
|
||||
|
||||
PyObject *Color_CreatePyObject(const float col[3], PyTypeObject *base_type)
|
||||
{
|
||||
ColorObject *self;
|
||||
@@ -1156,3 +1231,5 @@ PyObject *Color_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_sub
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -19,7 +19,8 @@ typedef struct {
|
||||
* be stored in py_data) or be a wrapper for data allocated through
|
||||
* Blender (stored in blend_data). This is an either/or struct not both. */
|
||||
|
||||
/* prototypes */
|
||||
/* Prototypes. */
|
||||
|
||||
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
|
||||
|
||||
@@ -19,45 +19,11 @@
|
||||
|
||||
#define EULER_SIZE 3
|
||||
|
||||
/* ----------------------------------mathutils.Euler() ------------------- */
|
||||
/* makes a new euler for you to play with */
|
||||
static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *seq = NULL;
|
||||
const char *order_str = NULL;
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities
|
||||
* \{ */
|
||||
|
||||
float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
|
||||
short order = EULER_ORDER_XYZ;
|
||||
|
||||
if (kwds && PyDict_Size(kwds)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"mathutils.Euler(): "
|
||||
"takes no keyword args");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (PyTuple_GET_SIZE(args)) {
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
ATTR_FALLTHROUGH;
|
||||
case 1:
|
||||
if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Euler_CreatePyObject(eul, order, type);
|
||||
}
|
||||
|
||||
/* internal use, assume read callback is done */
|
||||
/** Internal use, assume read callback is done. */
|
||||
static const char *euler_order_str(EulerObject *self)
|
||||
{
|
||||
static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
|
||||
@@ -96,8 +62,10 @@ short euler_order_from_string(const char *str, const char *error_prefix)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* NOTE: BaseMath_ReadCallback must be called beforehand. */
|
||||
static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
|
||||
/**
|
||||
* \note #BaseMath_ReadCallback must be called beforehand.
|
||||
*/
|
||||
static PyObject *Euler_to_tuple_ex(EulerObject *self, int ndigits)
|
||||
{
|
||||
PyObject *ret;
|
||||
int i;
|
||||
@@ -118,8 +86,53 @@ static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -----------------------------METHODS----------------------------
|
||||
* return a quaternion representation of the euler */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: `__new__` / `mathutils.Euler()`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *seq = NULL;
|
||||
const char *order_str = NULL;
|
||||
|
||||
float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
|
||||
short order = EULER_ORDER_XYZ;
|
||||
|
||||
if (kwds && PyDict_Size(kwds)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"mathutils.Euler(): "
|
||||
"takes no keyword args");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (PyTuple_GET_SIZE(args)) {
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
ATTR_FALLTHROUGH;
|
||||
case 1:
|
||||
if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Euler_CreatePyObject(eul, order, type);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Methods
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Euler_to_quaternion_doc,
|
||||
".. method:: to_quaternion()\n"
|
||||
@@ -141,7 +154,6 @@ static PyObject *Euler_to_quaternion(EulerObject *self)
|
||||
return Quaternion_CreatePyObject(quat, NULL);
|
||||
}
|
||||
|
||||
/* return a matrix representation of the euler */
|
||||
PyDoc_STRVAR(Euler_to_matrix_doc,
|
||||
".. method:: to_matrix()\n"
|
||||
"\n"
|
||||
@@ -279,9 +291,6 @@ static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* ----------------------------Euler.rotate()-----------------------
|
||||
* return a copy of the euler */
|
||||
|
||||
PyDoc_STRVAR(Euler_copy_doc,
|
||||
".. function:: copy()\n"
|
||||
"\n"
|
||||
@@ -308,8 +317,11 @@ static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
|
||||
return Euler_copy(self);
|
||||
}
|
||||
|
||||
/* ----------------------------print object (internal)--------------
|
||||
* print the object to screen */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: `__repr__` & `__str__`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Euler_repr(EulerObject *self)
|
||||
{
|
||||
@@ -319,7 +331,7 @@ static PyObject *Euler_repr(EulerObject *self)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tuple = Euler_ToTupleExt(self, -1);
|
||||
tuple = Euler_to_tuple_ex(self, -1);
|
||||
|
||||
ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
|
||||
|
||||
@@ -349,6 +361,12 @@ static PyObject *Euler_str(EulerObject *self)
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Rich Compare
|
||||
* \{ */
|
||||
|
||||
static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
@@ -390,6 +408,12 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
return Py_INCREF_RET(res);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Hash (`__hash__`)
|
||||
* \{ */
|
||||
|
||||
static Py_hash_t Euler_hash(EulerObject *self)
|
||||
{
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
@@ -403,15 +427,19 @@ static Py_hash_t Euler_hash(EulerObject *self)
|
||||
return mathutils_array_hash(self->eul, EULER_SIZE);
|
||||
}
|
||||
|
||||
/* ---------------------SEQUENCE PROTOCOLS------------------------ */
|
||||
/* ----------------------------len(object)------------------------ */
|
||||
/* sequence length */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Sequence Protocol
|
||||
* \{ */
|
||||
|
||||
/** Sequence length: `len(object)`. */
|
||||
static int Euler_len(EulerObject *UNUSED(self))
|
||||
{
|
||||
return EULER_SIZE;
|
||||
}
|
||||
/* ----------------------------object[]--------------------------- */
|
||||
/* sequence accessor (get) */
|
||||
|
||||
/** Sequence accessor (get): `x = object[i]`. */
|
||||
static PyObject *Euler_item(EulerObject *self, int i)
|
||||
{
|
||||
if (i < 0) {
|
||||
@@ -431,8 +459,8 @@ static PyObject *Euler_item(EulerObject *self, int i)
|
||||
|
||||
return PyFloat_FromDouble(self->eul[i]);
|
||||
}
|
||||
/* ----------------------------object[]------------------------- */
|
||||
/* sequence accessor (set) */
|
||||
|
||||
/** Sequence accessor (set): `object[i] = x`. */
|
||||
static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
|
||||
{
|
||||
float f;
|
||||
@@ -468,8 +496,8 @@ static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ----------------------------object[z:y]------------------------ */
|
||||
/* sequence slice (get) */
|
||||
|
||||
/** Sequence slice accessor (get): `x = object[i:j]`. */
|
||||
static PyObject *Euler_slice(EulerObject *self, int begin, int end)
|
||||
{
|
||||
PyObject *tuple;
|
||||
@@ -493,8 +521,8 @@ static PyObject *Euler_slice(EulerObject *self, int begin, int end)
|
||||
|
||||
return tuple;
|
||||
}
|
||||
/* ----------------------------object[z:y]------------------------ */
|
||||
/* sequence slice (set) */
|
||||
|
||||
/** Sequence slice accessor (set): `object[i:j] = x`. */
|
||||
static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
|
||||
{
|
||||
int i, size;
|
||||
@@ -531,6 +559,7 @@ static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (get): `x = object[...]`. */
|
||||
static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -567,6 +596,7 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (set): `object[...] = x`. */
|
||||
static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -599,18 +629,23 @@ static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *valu
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -----------------PROTCOL DECLARATIONS-------------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Sequence & Mapping Protocol Declarations
|
||||
* \{ */
|
||||
|
||||
static PySequenceMethods Euler_SeqMethods = {
|
||||
(lenfunc)Euler_len, /* sq_length */
|
||||
(binaryfunc)NULL, /* sq_concat */
|
||||
(ssizeargfunc)NULL, /* sq_repeat */
|
||||
(ssizeargfunc)Euler_item, /* sq_item */
|
||||
(ssizessizeargfunc)NULL, /* sq_slice (deprecated) */
|
||||
(ssizeobjargproc)Euler_ass_item, /* sq_ass_item */
|
||||
(ssizessizeobjargproc)NULL, /* sq_ass_slice (deprecated) */
|
||||
(objobjproc)NULL, /* sq_contains */
|
||||
(binaryfunc)NULL, /* sq_inplace_concat */
|
||||
(ssizeargfunc)NULL, /* sq_inplace_repeat */
|
||||
(lenfunc)Euler_len, /*sq_length*/
|
||||
(binaryfunc)NULL, /*sq_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_repeat*/
|
||||
(ssizeargfunc)Euler_item, /*sq_item*/
|
||||
(ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
|
||||
(ssizeobjargproc)Euler_ass_item, /*sq_ass_item*/
|
||||
(ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
|
||||
(objobjproc)NULL, /*sq_contains*/
|
||||
(binaryfunc)NULL, /*sq_inplace_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_inplace_repeat*/
|
||||
};
|
||||
|
||||
static PyMappingMethods Euler_AsMapping = {
|
||||
@@ -619,7 +654,13 @@ static PyMappingMethods Euler_AsMapping = {
|
||||
(objobjargproc)Euler_ass_subscript,
|
||||
};
|
||||
|
||||
/* euler axis, euler.x/y/z */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Get/Set Item Implementation
|
||||
* \{ */
|
||||
|
||||
/* Euler axis: `euler.x/y/z`. */
|
||||
|
||||
PyDoc_STRVAR(Euler_axis_doc, "Euler axis angle in radians.\n\n:type: float");
|
||||
static PyObject *Euler_axis_get(EulerObject *self, void *type)
|
||||
@@ -632,7 +673,7 @@ static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
|
||||
return Euler_ass_item(self, POINTER_AS_INT(type), value);
|
||||
}
|
||||
|
||||
/* rotation order */
|
||||
/* Euler rotation order: `euler.order`. */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Euler_order_doc,
|
||||
@@ -666,9 +707,12 @@ static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(clos
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python attributes get/set structure: */
|
||||
/*****************************************************************************/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Get/Set Item Definitions
|
||||
* \{ */
|
||||
|
||||
static PyGetSetDef Euler_getseters[] = {
|
||||
{"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
|
||||
{"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
|
||||
@@ -694,7 +738,12 @@ static PyGetSetDef Euler_getseters[] = {
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* -----------------------METHOD DEFINITIONS ---------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Method Definitions
|
||||
* \{ */
|
||||
|
||||
static struct PyMethodDef Euler_methods[] = {
|
||||
{"zero", (PyCFunction)Euler_zero, METH_NOARGS, Euler_zero_doc},
|
||||
{"to_matrix", (PyCFunction)Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
|
||||
@@ -711,7 +760,12 @@ static struct PyMethodDef Euler_methods[] = {
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
/* ------------------PY_OBECT DEFINITION-------------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: Python Object Definition
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
euler_doc,
|
||||
".. class:: Euler(angles, order='XYZ')\n"
|
||||
@@ -776,6 +830,12 @@ PyTypeObject euler_Type = {
|
||||
NULL, /* tp_del */
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Euler Type: C/API Constructors
|
||||
* \{ */
|
||||
|
||||
PyObject *Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
|
||||
{
|
||||
EulerObject *self;
|
||||
@@ -849,3 +909,5 @@ PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -22,6 +22,7 @@ typedef struct {
|
||||
* blender (stored in blend_data). This is an either/or struct not both */
|
||||
|
||||
/* prototypes */
|
||||
|
||||
PyObject *Euler_CreatePyObject(const float eul[3],
|
||||
short order,
|
||||
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
@@ -32,6 +32,10 @@ static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
|
||||
MatrixObject *self);
|
||||
static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities
|
||||
* \{ */
|
||||
|
||||
static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
|
||||
{
|
||||
if ((vec->vec_num != mat->col_num) || (row >= mat->row_num)) {
|
||||
@@ -56,9 +60,242 @@ static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* matrix row callbacks
|
||||
* this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */
|
||||
/** When a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4. */
|
||||
static void matrix_3x3_as_4x4(float mat[16])
|
||||
{
|
||||
mat[10] = mat[8];
|
||||
mat[9] = mat[7];
|
||||
mat[8] = mat[6];
|
||||
mat[7] = 0.0f;
|
||||
mat[6] = mat[5];
|
||||
mat[5] = mat[4];
|
||||
mat[4] = mat[3];
|
||||
mat[3] = 0.0f;
|
||||
}
|
||||
|
||||
void matrix_as_3x3(float mat[3][3], MatrixObject *self)
|
||||
{
|
||||
copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
|
||||
copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
|
||||
copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
|
||||
}
|
||||
|
||||
static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
|
||||
{
|
||||
BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
|
||||
BLI_assert(mat_dst != mat_src);
|
||||
|
||||
memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
|
||||
}
|
||||
|
||||
static void matrix_unit_internal(MatrixObject *self)
|
||||
{
|
||||
const int mat_size = sizeof(float) * (self->col_num * self->row_num);
|
||||
memset(self->matrix, 0x0, mat_size);
|
||||
const int col_row_max = min_ii(self->col_num, self->row_num);
|
||||
const int row_num = self->row_num;
|
||||
for (int col = 0; col < col_row_max; col++) {
|
||||
self->matrix[(col * row_num) + col] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/** Transposes memory layout, row/columns don't have to match. */
|
||||
static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
|
||||
{
|
||||
ushort col, row;
|
||||
uint i = 0;
|
||||
|
||||
for (row = 0; row < mat_src->row_num; row++) {
|
||||
for (col = 0; col < mat_src->col_num; 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)
|
||||
{
|
||||
if (self->col_num == 2) {
|
||||
return determinant_m2(MATRIX_ITEM(self, 0, 0),
|
||||
MATRIX_ITEM(self, 0, 1),
|
||||
MATRIX_ITEM(self, 1, 0),
|
||||
MATRIX_ITEM(self, 1, 1));
|
||||
}
|
||||
if (self->col_num == 3) {
|
||||
return determinant_m3(MATRIX_ITEM(self, 0, 0),
|
||||
MATRIX_ITEM(self, 0, 1),
|
||||
MATRIX_ITEM(self, 0, 2),
|
||||
MATRIX_ITEM(self, 1, 0),
|
||||
MATRIX_ITEM(self, 1, 1),
|
||||
MATRIX_ITEM(self, 1, 2),
|
||||
MATRIX_ITEM(self, 2, 0),
|
||||
MATRIX_ITEM(self, 2, 1),
|
||||
MATRIX_ITEM(self, 2, 2));
|
||||
}
|
||||
|
||||
return determinant_m4((const float(*)[4])self->matrix);
|
||||
}
|
||||
|
||||
static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
|
||||
{
|
||||
/* calculate the classical adjoint */
|
||||
switch (dim) {
|
||||
case 2: {
|
||||
adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void matrix_invert_with_det_n_internal(float *mat_dst,
|
||||
const float *mat_src,
|
||||
const float det,
|
||||
const ushort dim)
|
||||
{
|
||||
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
|
||||
ushort i, j, k;
|
||||
|
||||
BLI_assert(det != 0.0f);
|
||||
|
||||
adjoint_matrix_n(mat, mat_src, dim);
|
||||
|
||||
/* divide by determinant & set values */
|
||||
k = 0;
|
||||
for (i = 0; i < dim; i++) { /* col_num */
|
||||
for (j = 0; j < dim; j++) { /* row_num */
|
||||
mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \param r_mat: can be from `self->matrix` or not.
|
||||
*/
|
||||
static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
|
||||
{
|
||||
float det;
|
||||
BLI_assert(self->col_num == self->row_num);
|
||||
det = matrix_determinant_internal(self);
|
||||
|
||||
if (det != 0.0f) {
|
||||
matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `matrix_invert_internal` but should never error.
|
||||
* \param r_mat: can be from `self->matrix` or not.
|
||||
*/
|
||||
static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
|
||||
{
|
||||
float det;
|
||||
float *in_mat = self->matrix;
|
||||
BLI_assert(self->col_num == self->row_num);
|
||||
det = matrix_determinant_internal(self);
|
||||
|
||||
if (det == 0.0f) {
|
||||
const float eps = PSEUDOINVERSE_EPSILON;
|
||||
|
||||
/* We will copy self->matrix into r_mat (if needed),
|
||||
* and modify it in place to add diagonal epsilon. */
|
||||
in_mat = r_mat;
|
||||
|
||||
switch (self->col_num) {
|
||||
case 2: {
|
||||
float(*mat)[2] = (float(*)[2])in_mat;
|
||||
|
||||
if (in_mat != self->matrix) {
|
||||
copy_m2_m2(mat, (const float(*)[2])self->matrix);
|
||||
}
|
||||
mat[0][0] += eps;
|
||||
mat[1][1] += eps;
|
||||
|
||||
if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
|
||||
unit_m2(mat);
|
||||
det = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
float(*mat)[3] = (float(*)[3])in_mat;
|
||||
|
||||
if (in_mat != self->matrix) {
|
||||
copy_m3_m3(mat, (const float(*)[3])self->matrix);
|
||||
}
|
||||
mat[0][0] += eps;
|
||||
mat[1][1] += eps;
|
||||
mat[2][2] += eps;
|
||||
|
||||
if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
|
||||
unit_m3(mat);
|
||||
det = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
float(*mat)[4] = (float(*)[4])in_mat;
|
||||
|
||||
if (in_mat != self->matrix) {
|
||||
copy_m4_m4(mat, (const float(*)[4])self->matrix);
|
||||
}
|
||||
mat[0][0] += eps;
|
||||
mat[1][1] += eps;
|
||||
mat[2][2] += eps;
|
||||
mat[3][3] += eps;
|
||||
|
||||
if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
|
||||
unit_m4(mat);
|
||||
det = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
|
||||
}
|
||||
|
||||
static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
|
||||
MatrixObject *self)
|
||||
{
|
||||
PyObject *ret = Matrix_copy(self);
|
||||
if (ret) {
|
||||
PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
|
||||
if (ret_dummy) {
|
||||
Py_DECREF(ret_dummy);
|
||||
return ret;
|
||||
}
|
||||
/* error */
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy may fail if the read callback errors out */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Row Callbacks
|
||||
* This is so you can do `matrix[i][j] = val` or `matrix.row[i][j] = val`.
|
||||
* \{ */
|
||||
|
||||
uchar mathutils_matrix_row_cb_index = -1;
|
||||
|
||||
@@ -147,9 +384,12 @@ Mathutils_Callback mathutils_matrix_row_cb = {
|
||||
mathutils_matrix_row_set_index,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* matrix row callbacks
|
||||
* this is so you can do matrix.col[i][j] = val */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Column Callbacks
|
||||
* This is so you can do `matrix.col[i][j] = val`.
|
||||
* \{ */
|
||||
|
||||
uchar mathutils_matrix_col_cb_index = -1;
|
||||
|
||||
@@ -246,10 +486,14 @@ Mathutils_Callback mathutils_matrix_col_cb = {
|
||||
mathutils_matrix_col_set_index,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* matrix row callbacks
|
||||
* this is so you can do matrix.translation = val
|
||||
* NOTE: this is _exactly like matrix.col except the 4th component is always omitted. */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Translation Callbacks
|
||||
* This is so you can do `matrix.translation = val`.
|
||||
*
|
||||
* \note this is _exactly like matrix.col except the 4th component is always omitted.
|
||||
* \{ */
|
||||
|
||||
uchar mathutils_matrix_translation_cb_index = -1;
|
||||
|
||||
@@ -326,11 +570,12 @@ Mathutils_Callback mathutils_matrix_translation_cb = {
|
||||
mathutils_matrix_translation_set_index,
|
||||
};
|
||||
|
||||
/* matrix column callbacks, this is so you can do `matrix.translation = Vector()`. */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: `__new__` / `mathutils.Matrix()`
|
||||
* \{ */
|
||||
|
||||
/* ----------------------------------mathutils.Matrix() ----------------- */
|
||||
/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
|
||||
/* create a new matrix type */
|
||||
static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
if (kwds && PyDict_Size(kwds)) {
|
||||
@@ -379,41 +624,13 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
|
||||
MatrixObject *self)
|
||||
{
|
||||
PyObject *ret = Matrix_copy(self);
|
||||
if (ret) {
|
||||
PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
|
||||
if (ret_dummy) {
|
||||
Py_DECREF(ret_dummy);
|
||||
return ret;
|
||||
}
|
||||
/* error */
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
/** \} */
|
||||
|
||||
/* copy may fail if the read callback errors out */
|
||||
return NULL;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Class Methods
|
||||
* \{ */
|
||||
|
||||
/* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
|
||||
static void matrix_3x3_as_4x4(float mat[16])
|
||||
{
|
||||
mat[10] = mat[8];
|
||||
mat[9] = mat[7];
|
||||
mat[8] = mat[6];
|
||||
mat[7] = 0.0f;
|
||||
mat[6] = mat[5];
|
||||
mat[5] = mat[4];
|
||||
mat[4] = mat[3];
|
||||
mat[3] = 0.0f;
|
||||
}
|
||||
|
||||
/*-----------------------CLASS-METHODS----------------------------*/
|
||||
|
||||
/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
|
||||
/** Identity constructor: `mathutils.Matrix.Identity()`. */
|
||||
PyDoc_STRVAR(C_Matrix_Identity_doc,
|
||||
".. classmethod:: Identity(size)\n"
|
||||
"\n"
|
||||
@@ -441,6 +658,7 @@ static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
|
||||
return Matrix_CreatePyObject(NULL, matSize, matSize, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
/** Rotation constructor: `mathutils.Matrix.Rotation()`. */
|
||||
PyDoc_STRVAR(C_Matrix_Rotation_doc,
|
||||
".. classmethod:: Rotation(angle, size, axis)\n"
|
||||
"\n"
|
||||
@@ -460,25 +678,8 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
|
||||
PyObject *vec = NULL;
|
||||
const char *axis = NULL;
|
||||
int matSize;
|
||||
double angle; /* use double because of precision problems at high values */
|
||||
float mat[16] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
};
|
||||
double angle; /* Use double because of precision problems at high values. */
|
||||
float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
|
||||
return NULL;
|
||||
@@ -545,6 +746,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
|
||||
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
/** Translation constructor: `mathutils.Matrix.Translation()`. */
|
||||
PyDoc_STRVAR(C_Matrix_Translation_doc,
|
||||
".. classmethod:: Translation(vector)\n"
|
||||
"\n"
|
||||
@@ -567,7 +769,7 @@ static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
|
||||
|
||||
return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
|
||||
}
|
||||
/* ----------------------------------mathutils.Matrix.Diagonal() ------------- */
|
||||
|
||||
PyDoc_STRVAR(C_Matrix_Diagonal_doc,
|
||||
".. classmethod:: Diagonal(vector)\n"
|
||||
"\n"
|
||||
@@ -577,6 +779,7 @@ PyDoc_STRVAR(C_Matrix_Diagonal_doc,
|
||||
" :type vector: :class:`Vector`\n"
|
||||
" :return: A diagonal matrix.\n"
|
||||
" :rtype: :class:`Matrix`\n");
|
||||
/** Diagonal constructor: `mathutils.Matrix.Diagonal()`. */
|
||||
static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
|
||||
{
|
||||
float mat[16] = {0.0f};
|
||||
@@ -595,8 +798,8 @@ static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
|
||||
|
||||
return Matrix_CreatePyObject(mat, size, size, (PyTypeObject *)cls);
|
||||
}
|
||||
/* ----------------------------------mathutils.Matrix.Scale() ------------- */
|
||||
/* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
|
||||
|
||||
/** Scale constructor: `mathutils.Matrix.Scale()`. */
|
||||
PyDoc_STRVAR(C_Matrix_Scale_doc,
|
||||
".. classmethod:: Scale(factor, size, axis)\n"
|
||||
"\n"
|
||||
@@ -617,24 +820,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
|
||||
float tvec[3];
|
||||
float factor;
|
||||
int matSize;
|
||||
float mat[16] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
};
|
||||
float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
|
||||
return NULL;
|
||||
@@ -700,8 +886,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
|
||||
/* pass to matrix creation */
|
||||
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. */
|
||||
/** Orthographic projection constructor: `mathutils.Matrix.OrthoProjection()`. */
|
||||
PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
|
||||
".. classmethod:: OrthoProjection(axis, size)\n"
|
||||
"\n"
|
||||
@@ -721,24 +906,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
|
||||
|
||||
int matSize, x;
|
||||
float norm = 0.0f;
|
||||
float mat[16] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
};
|
||||
float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
|
||||
return NULL;
|
||||
@@ -837,6 +1005,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
|
||||
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
/** Shear constructor: `mathutils.Matrix.Shear()`. */
|
||||
PyDoc_STRVAR(C_Matrix_Shear_doc,
|
||||
".. classmethod:: Shear(plane, size, factor)\n"
|
||||
"\n"
|
||||
@@ -857,24 +1026,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
|
||||
int matSize;
|
||||
const char *plane;
|
||||
PyObject *fac;
|
||||
float mat[16] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
};
|
||||
float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
|
||||
return NULL;
|
||||
@@ -1051,205 +1203,12 @@ static PyObject *C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
|
||||
return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
void matrix_as_3x3(float mat[3][3], MatrixObject *self)
|
||||
{
|
||||
copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
|
||||
copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
|
||||
copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
|
||||
}
|
||||
/** \} */
|
||||
|
||||
static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
|
||||
{
|
||||
BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
|
||||
BLI_assert(mat_dst != mat_src);
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: To Quaternion
|
||||
* \{ */
|
||||
|
||||
memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
|
||||
}
|
||||
|
||||
static void matrix_unit_internal(MatrixObject *self)
|
||||
{
|
||||
const int mat_size = sizeof(float) * (self->col_num * self->row_num);
|
||||
memset(self->matrix, 0x0, mat_size);
|
||||
const int col_row_max = min_ii(self->col_num, self->row_num);
|
||||
const int row_num = self->row_num;
|
||||
for (int col = 0; col < col_row_max; col++) {
|
||||
self->matrix[(col * row_num) + col] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* transposes memory layout, rol/col's don't have to match */
|
||||
static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
|
||||
{
|
||||
ushort col, row;
|
||||
uint i = 0;
|
||||
|
||||
for (row = 0; row < mat_src->row_num; row++) {
|
||||
for (col = 0; col < mat_src->col_num; 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)
|
||||
{
|
||||
if (self->col_num == 2) {
|
||||
return determinant_m2(MATRIX_ITEM(self, 0, 0),
|
||||
MATRIX_ITEM(self, 0, 1),
|
||||
MATRIX_ITEM(self, 1, 0),
|
||||
MATRIX_ITEM(self, 1, 1));
|
||||
}
|
||||
if (self->col_num == 3) {
|
||||
return determinant_m3(MATRIX_ITEM(self, 0, 0),
|
||||
MATRIX_ITEM(self, 0, 1),
|
||||
MATRIX_ITEM(self, 0, 2),
|
||||
MATRIX_ITEM(self, 1, 0),
|
||||
MATRIX_ITEM(self, 1, 1),
|
||||
MATRIX_ITEM(self, 1, 2),
|
||||
MATRIX_ITEM(self, 2, 0),
|
||||
MATRIX_ITEM(self, 2, 1),
|
||||
MATRIX_ITEM(self, 2, 2));
|
||||
}
|
||||
|
||||
return determinant_m4((const float(*)[4])self->matrix);
|
||||
}
|
||||
|
||||
static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
|
||||
{
|
||||
/* calculate the classical adjoint */
|
||||
switch (dim) {
|
||||
case 2: {
|
||||
adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void matrix_invert_with_det_n_internal(float *mat_dst,
|
||||
const float *mat_src,
|
||||
const float det,
|
||||
const ushort dim)
|
||||
{
|
||||
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
|
||||
ushort i, j, k;
|
||||
|
||||
BLI_assert(det != 0.0f);
|
||||
|
||||
adjoint_matrix_n(mat, mat_src, dim);
|
||||
|
||||
/* divide by determinant & set values */
|
||||
k = 0;
|
||||
for (i = 0; i < dim; i++) { /* col_num */
|
||||
for (j = 0; j < dim; j++) { /* row_num */
|
||||
mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \param r_mat: can be from `self->matrix` or not.
|
||||
*/
|
||||
static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
|
||||
{
|
||||
float det;
|
||||
BLI_assert(self->col_num == self->row_num);
|
||||
det = matrix_determinant_internal(self);
|
||||
|
||||
if (det != 0.0f) {
|
||||
matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `matrix_invert_internal` but should never error.
|
||||
* \param r_mat: can be from `self->matrix` or not.
|
||||
*/
|
||||
static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
|
||||
{
|
||||
float det;
|
||||
float *in_mat = self->matrix;
|
||||
BLI_assert(self->col_num == self->row_num);
|
||||
det = matrix_determinant_internal(self);
|
||||
|
||||
if (det == 0.0f) {
|
||||
const float eps = PSEUDOINVERSE_EPSILON;
|
||||
|
||||
/* We will copy self->matrix into r_mat (if needed),
|
||||
* and modify it in place to add diagonal epsilon. */
|
||||
in_mat = r_mat;
|
||||
|
||||
switch (self->col_num) {
|
||||
case 2: {
|
||||
float(*mat)[2] = (float(*)[2])in_mat;
|
||||
|
||||
if (in_mat != self->matrix) {
|
||||
copy_m2_m2(mat, (const float(*)[2])self->matrix);
|
||||
}
|
||||
mat[0][0] += eps;
|
||||
mat[1][1] += eps;
|
||||
|
||||
if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
|
||||
unit_m2(mat);
|
||||
det = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
float(*mat)[3] = (float(*)[3])in_mat;
|
||||
|
||||
if (in_mat != self->matrix) {
|
||||
copy_m3_m3(mat, (const float(*)[3])self->matrix);
|
||||
}
|
||||
mat[0][0] += eps;
|
||||
mat[1][1] += eps;
|
||||
mat[2][2] += eps;
|
||||
|
||||
if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
|
||||
unit_m3(mat);
|
||||
det = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
float(*mat)[4] = (float(*)[4])in_mat;
|
||||
|
||||
if (in_mat != self->matrix) {
|
||||
copy_m4_m4(mat, (const float(*)[4])self->matrix);
|
||||
}
|
||||
mat[0][0] += eps;
|
||||
mat[1][1] += eps;
|
||||
mat[2][2] += eps;
|
||||
mat[3][3] += eps;
|
||||
|
||||
if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
|
||||
unit_m4(mat);
|
||||
det = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
|
||||
}
|
||||
|
||||
/*-----------------------------METHODS----------------------------*/
|
||||
PyDoc_STRVAR(Matrix_to_quaternion_doc,
|
||||
".. method:: to_quaternion()\n"
|
||||
"\n"
|
||||
@@ -1282,7 +1241,12 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self)
|
||||
return Quaternion_CreatePyObject(quat, NULL);
|
||||
}
|
||||
|
||||
/*---------------------------matrix.toEuler() --------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: To Euler
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_to_euler_doc,
|
||||
".. method:: to_euler(order, euler_compat)\n"
|
||||
"\n"
|
||||
@@ -1367,6 +1331,12 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
|
||||
return Euler_CreatePyObject(eul, order, NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Resize
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_resize_4x4_doc,
|
||||
".. method:: resize_4x4()\n"
|
||||
"\n"
|
||||
@@ -1411,6 +1381,12 @@ static PyObject *Matrix_resize_4x4(MatrixObject *self)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: To NxN
|
||||
* \{ */
|
||||
|
||||
static PyObject *Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
|
||||
{
|
||||
const int mat_size = sizeof(float) * (col_num * row_num);
|
||||
@@ -1480,6 +1456,12 @@ static PyObject *Matrix_to_4x4(MatrixObject *self)
|
||||
return Matrix_to_NxN(self, 4, 4);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: To Translation/Scale
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_to_translation_doc,
|
||||
".. method:: to_translation()\n"
|
||||
"\n"
|
||||
@@ -1539,9 +1521,13 @@ static PyObject *Matrix_to_scale(MatrixObject *self)
|
||||
return Vector_CreatePyObject(size, 3, NULL);
|
||||
}
|
||||
|
||||
/*---------------------------matrix.invert() ---------------------*/
|
||||
/** \} */
|
||||
|
||||
/* re-usable checks for invert */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Invert
|
||||
* \{ */
|
||||
|
||||
/** Re-usable checks for invert. */
|
||||
static bool matrix_invert_is_compat(const MatrixObject *self)
|
||||
{
|
||||
if (self->col_num != self->row_num) {
|
||||
@@ -1763,7 +1749,12 @@ static PyObject *Matrix_inverted_safe(MatrixObject *self)
|
||||
return Matrix_copy_notest(self, mat);
|
||||
}
|
||||
|
||||
/*---------------------------matrix.adjugate() ---------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Adjugate
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Matrix_adjugate_doc,
|
||||
".. method:: adjugate()\n"
|
||||
@@ -1852,7 +1843,12 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*---------------------------matrix.decompose() ---------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Decompose
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_decompose_doc,
|
||||
".. method:: decompose()\n"
|
||||
"\n"
|
||||
@@ -1890,6 +1886,12 @@ static PyObject *Matrix_decompose(MatrixObject *self)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Linear Interpolate (lerp)
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_lerp_doc,
|
||||
".. function:: lerp(other, factor)\n"
|
||||
"\n"
|
||||
@@ -1947,7 +1949,6 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
|
||||
return Matrix_CreatePyObject(mat, self->col_num, self->row_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/*---------------------------matrix.determinant() ----------------*/
|
||||
PyDoc_STRVAR(
|
||||
Matrix_determinant_doc,
|
||||
".. method:: determinant()\n"
|
||||
@@ -1973,7 +1974,13 @@ static PyObject *Matrix_determinant(MatrixObject *self)
|
||||
|
||||
return PyFloat_FromDouble((double)matrix_determinant_internal(self));
|
||||
}
|
||||
/*---------------------------matrix.transpose() ------------------*/
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Transpose
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Matrix_transpose_doc,
|
||||
".. method:: transpose()\n"
|
||||
@@ -2022,7 +2029,12 @@ static PyObject *Matrix_transposed(MatrixObject *self)
|
||||
return matrix__apply_to_copy(Matrix_transpose, self);
|
||||
}
|
||||
|
||||
/*---------------------------matrix.normalize() ------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Normalize
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_normalize_doc,
|
||||
".. method:: normalize()\n"
|
||||
"\n"
|
||||
@@ -2068,7 +2080,12 @@ static PyObject *Matrix_normalized(MatrixObject *self)
|
||||
return matrix__apply_to_copy(Matrix_normalize, self);
|
||||
}
|
||||
|
||||
/*---------------------------matrix.zero() -----------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Zero
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_zero_doc,
|
||||
".. method:: zero()\n"
|
||||
"\n"
|
||||
@@ -2089,7 +2106,13 @@ static PyObject *Matrix_zero(MatrixObject *self)
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
/*---------------------------matrix.identity(() ------------------*/
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Set Identity
|
||||
* \{ */
|
||||
|
||||
static void matrix_identity_internal(MatrixObject *self)
|
||||
{
|
||||
BLI_assert((self->col_num == self->row_num) && (self->row_num <= 4));
|
||||
@@ -2137,8 +2160,13 @@ static PyObject *Matrix_identity(MatrixObject *self)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*---------------------------Matrix.copy() ------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Methods: Copy
|
||||
* \{ */
|
||||
|
||||
/** Copy `Matrix.copy()` */
|
||||
static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
|
||||
{
|
||||
return Matrix_CreatePyObject((const float *)matrix, self->col_num, self->row_num, Py_TYPE(self));
|
||||
@@ -2159,6 +2187,8 @@ static PyObject *Matrix_copy(MatrixObject *self)
|
||||
|
||||
return Matrix_copy_notest(self, self->matrix);
|
||||
}
|
||||
|
||||
/** Deep-copy `Matrix.deepcopy()` */
|
||||
static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
|
||||
{
|
||||
if (!PyC_CheckArgs_DeepCopy(args)) {
|
||||
@@ -2167,8 +2197,12 @@ static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
|
||||
return Matrix_copy(self);
|
||||
}
|
||||
|
||||
/*----------------------------print object (internal)-------------*/
|
||||
/* print the object to screen */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: `__repr__` & `__str__`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Matrix_repr(MatrixObject *self)
|
||||
{
|
||||
int col, row;
|
||||
@@ -2257,6 +2291,12 @@ static PyObject *Matrix_str(MatrixObject *self)
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Rich Compare
|
||||
* \{ */
|
||||
|
||||
static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
@@ -2298,6 +2338,12 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
return Py_INCREF_RET(res);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Hash (`__hash__`)
|
||||
* \{ */
|
||||
|
||||
static Py_hash_t Matrix_hash(MatrixObject *self)
|
||||
{
|
||||
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
|
||||
@@ -2315,16 +2361,22 @@ static Py_hash_t Matrix_hash(MatrixObject *self)
|
||||
return mathutils_array_hash(mat, self->row_num * self->col_num);
|
||||
}
|
||||
|
||||
/*---------------------SEQUENCE PROTOCOLS------------------------
|
||||
* ----------------------------len(object)------------------------
|
||||
* sequence length */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Sequence & Mapping Protocol Implementation
|
||||
* \{ */
|
||||
|
||||
/** Sequence length: `len(object)`. */
|
||||
static int Matrix_len(MatrixObject *self)
|
||||
{
|
||||
return self->row_num;
|
||||
}
|
||||
/*----------------------------object[]---------------------------
|
||||
* sequence accessor (get)
|
||||
* the wrapped vector gives direct access to the matrix data */
|
||||
|
||||
/**
|
||||
* Sequence accessor (get): `x = object[i]`.
|
||||
* \note the wrapped vector gives direct access to the matrix data.
|
||||
*/
|
||||
static PyObject *Matrix_item_row(MatrixObject *self, int row)
|
||||
{
|
||||
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
|
||||
@@ -2340,7 +2392,10 @@ static PyObject *Matrix_item_row(MatrixObject *self, int row)
|
||||
return Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, row);
|
||||
}
|
||||
/* same but column access */
|
||||
/**
|
||||
* Sequence accessor (get): `x = object.col[i]`.
|
||||
* \note the wrapped vector gives direct access to the matrix data.
|
||||
*/
|
||||
static PyObject *Matrix_item_col(MatrixObject *self, int col)
|
||||
{
|
||||
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
|
||||
@@ -2357,9 +2412,7 @@ static PyObject *Matrix_item_col(MatrixObject *self, int col)
|
||||
(PyObject *)self, self->row_num, mathutils_matrix_col_cb_index, col);
|
||||
}
|
||||
|
||||
/*----------------------------object[]-------------------------
|
||||
* sequence accessor (set) */
|
||||
|
||||
/** Sequence accessor (set): `object[i] = x`. */
|
||||
static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
|
||||
{
|
||||
int col;
|
||||
@@ -2386,6 +2439,8 @@ static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
|
||||
(void)BaseMath_WriteCallback(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sequence accessor (set): `object.col[i] = x`. */
|
||||
static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
|
||||
{
|
||||
int row;
|
||||
@@ -2413,8 +2468,7 @@ static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------object[z:y]------------------------
|
||||
* Sequence slice (get). */
|
||||
/** Sequence slice accessor (get): `x = object[i:j]`. */
|
||||
static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
|
||||
{
|
||||
|
||||
@@ -2439,8 +2493,8 @@ static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
|
||||
|
||||
return tuple;
|
||||
}
|
||||
/*----------------------------object[z:y]------------------------
|
||||
* Sequence slice (set). */
|
||||
|
||||
/** Sequence slice accessor (set): `object[i:j] = x`. */
|
||||
static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
|
||||
{
|
||||
PyObject *value_fast;
|
||||
@@ -2500,8 +2554,84 @@ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *va
|
||||
(void)BaseMath_WriteCallback(self);
|
||||
return 0;
|
||||
}
|
||||
/*------------------------NUMERIC PROTOCOLS----------------------
|
||||
*------------------------obj + obj------------------------------*/
|
||||
|
||||
/** Sequence generic subscript (get): `x = object[...]`. */
|
||||
static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i;
|
||||
i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
if (i < 0) {
|
||||
i += self->row_num;
|
||||
}
|
||||
return Matrix_item_row(self, i);
|
||||
}
|
||||
if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step, slicelength;
|
||||
|
||||
if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (slicelength <= 0) {
|
||||
return PyTuple_New(0);
|
||||
}
|
||||
if (step == 1) {
|
||||
return Matrix_slice(self, start, stop);
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyErr_Format(
|
||||
PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (set): `object[...] = x`. */
|
||||
static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
if (i < 0) {
|
||||
i += self->row_num;
|
||||
}
|
||||
return Matrix_ass_item_row(self, i, value);
|
||||
}
|
||||
if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step, slicelength;
|
||||
|
||||
if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
return Matrix_ass_slice(self, start, stop, value);
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyErr_Format(
|
||||
PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Numeric Protocol Implementation
|
||||
* \{ */
|
||||
|
||||
/** Addition: `object + object`. */
|
||||
static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
|
||||
{
|
||||
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
|
||||
@@ -2534,8 +2664,8 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
|
||||
|
||||
return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
|
||||
}
|
||||
/*------------------------obj - obj------------------------------
|
||||
* subtraction */
|
||||
|
||||
/** Subtraction: `object - object`. */
|
||||
static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
|
||||
{
|
||||
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
|
||||
@@ -2568,8 +2698,8 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
|
||||
|
||||
return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
|
||||
}
|
||||
/*------------------------obj * obj------------------------------
|
||||
* element-wise multiplication */
|
||||
|
||||
/** Multiplication (element-wise): `object * object`. */
|
||||
static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
|
||||
{
|
||||
float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
|
||||
@@ -2631,8 +2761,8 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
|
||||
Py_TYPE(m2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
/*------------------------obj *= obj------------------------------
|
||||
* In place element-wise multiplication */
|
||||
|
||||
/** Multiplication in-place (element-wise): `object *= object`. */
|
||||
static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
|
||||
{
|
||||
float scalar;
|
||||
@@ -2680,8 +2810,8 @@ static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
|
||||
Py_INCREF(m1);
|
||||
return m1;
|
||||
}
|
||||
/*------------------------obj @ obj------------------------------
|
||||
* matrix multiplication */
|
||||
|
||||
/** Multiplication (matrix multiply): `object @ object`. */
|
||||
static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
|
||||
{
|
||||
int vec_num;
|
||||
@@ -2756,8 +2886,8 @@ static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
|
||||
Py_TYPE(m2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
/*------------------------obj @= obj------------------------------
|
||||
* In place matrix multiplication */
|
||||
|
||||
/** Multiplication in-place (matrix multiply): `object @= object`. */
|
||||
static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
|
||||
{
|
||||
MatrixObject *mat1 = NULL, *mat2 = NULL;
|
||||
@@ -2816,88 +2946,25 @@ static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
|
||||
return m1;
|
||||
}
|
||||
|
||||
/*-----------------PROTOCOL DECLARATIONS--------------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Protocol Declarations
|
||||
* \{ */
|
||||
|
||||
static PySequenceMethods Matrix_SeqMethods = {
|
||||
(lenfunc)Matrix_len, /* sq_length */
|
||||
(binaryfunc)NULL, /* sq_concat */
|
||||
(ssizeargfunc)NULL, /* sq_repeat */
|
||||
(ssizeargfunc)Matrix_item_row, /* sq_item */
|
||||
(ssizessizeargfunc)NULL, /* sq_slice, deprecated */
|
||||
(ssizeobjargproc)Matrix_ass_item_row, /* sq_ass_item */
|
||||
(ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
|
||||
(objobjproc)NULL, /* sq_contains */
|
||||
(binaryfunc)NULL, /* sq_inplace_concat */
|
||||
(ssizeargfunc)NULL, /* sq_inplace_repeat */
|
||||
(lenfunc)Matrix_len, /*sq_length*/
|
||||
(binaryfunc)NULL, /*sq_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_repeat*/
|
||||
(ssizeargfunc)Matrix_item_row, /*sq_item*/
|
||||
(ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
|
||||
(ssizeobjargproc)Matrix_ass_item_row, /*sq_ass_item*/
|
||||
(ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
|
||||
(objobjproc)NULL, /*sq_contains*/
|
||||
(binaryfunc)NULL, /*sq_inplace_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_inplace_repeat*/
|
||||
};
|
||||
|
||||
static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i;
|
||||
i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
if (i < 0) {
|
||||
i += self->row_num;
|
||||
}
|
||||
return Matrix_item_row(self, i);
|
||||
}
|
||||
if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step, slicelength;
|
||||
|
||||
if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (slicelength <= 0) {
|
||||
return PyTuple_New(0);
|
||||
}
|
||||
if (step == 1) {
|
||||
return Matrix_slice(self, start, stop);
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyErr_Format(
|
||||
PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
if (i < 0) {
|
||||
i += self->row_num;
|
||||
}
|
||||
return Matrix_ass_item_row(self, i, value);
|
||||
}
|
||||
if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step, slicelength;
|
||||
|
||||
if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
return Matrix_ass_slice(self, start, stop, value);
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyErr_Format(
|
||||
PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyMappingMethods Matrix_AsMapping = {
|
||||
(lenfunc)Matrix_len,
|
||||
(binaryfunc)Matrix_subscript,
|
||||
@@ -2924,25 +2991,31 @@ static PyNumberMethods Matrix_NumMethods = {
|
||||
NULL, /*nb_int*/
|
||||
NULL, /*nb_reserved*/
|
||||
NULL, /*nb_float*/
|
||||
NULL, /* nb_inplace_add */
|
||||
NULL, /* nb_inplace_subtract */
|
||||
(binaryfunc)Matrix_imul, /* nb_inplace_multiply */
|
||||
NULL, /* nb_inplace_remainder */
|
||||
NULL, /* nb_inplace_power */
|
||||
NULL, /* nb_inplace_lshift */
|
||||
NULL, /* nb_inplace_rshift */
|
||||
NULL, /* nb_inplace_and */
|
||||
NULL, /* nb_inplace_xor */
|
||||
NULL, /* nb_inplace_or */
|
||||
NULL, /* nb_floor_divide */
|
||||
NULL, /* nb_true_divide */
|
||||
NULL, /* nb_inplace_floor_divide */
|
||||
NULL, /* nb_inplace_true_divide */
|
||||
NULL, /* nb_index */
|
||||
(binaryfunc)Matrix_matmul, /* nb_matrix_multiply */
|
||||
(binaryfunc)Matrix_imatmul, /* nb_inplace_matrix_multiply */
|
||||
NULL, /*nb_inplace_add*/
|
||||
NULL, /*nb_inplace_subtract*/
|
||||
(binaryfunc)Matrix_imul, /*nb_inplace_multiply*/
|
||||
NULL, /*nb_inplace_remainder*/
|
||||
NULL, /*nb_inplace_power*/
|
||||
NULL, /*nb_inplace_lshift*/
|
||||
NULL, /*nb_inplace_rshift*/
|
||||
NULL, /*nb_inplace_and*/
|
||||
NULL, /*nb_inplace_xor*/
|
||||
NULL, /*nb_inplace_or*/
|
||||
NULL, /*nb_floor_divide*/
|
||||
NULL, /*nb_true_divide*/
|
||||
NULL, /*nb_inplace_floor_divide*/
|
||||
NULL, /*nb_inplace_true_divide*/
|
||||
NULL, /*nb_index*/
|
||||
(binaryfunc)Matrix_matmul, /*nb_matrix_multiply*/
|
||||
(binaryfunc)Matrix_imatmul, /*nb_inplace_matrix_multiply*/
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Get/Set Item Implementation
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Matrix_translation_doc, "The translation component of the matrix.\n\n:type: Vector");
|
||||
static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
|
||||
{
|
||||
@@ -3099,9 +3172,12 @@ static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python attributes get/set structure: */
|
||||
/*****************************************************************************/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Get/Set Item Definitions
|
||||
* \{ */
|
||||
|
||||
static PyGetSetDef Matrix_getseters[] = {
|
||||
{"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
|
||||
{"translation",
|
||||
@@ -3141,7 +3217,12 @@ static PyGetSetDef Matrix_getseters[] = {
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------METHOD DEFINITIONS ----------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Method Definitions
|
||||
* \{ */
|
||||
|
||||
static struct PyMethodDef Matrix_methods[] = {
|
||||
/* Derived values. */
|
||||
{"determinant", (PyCFunction)Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
|
||||
@@ -3205,7 +3286,12 @@ static struct PyMethodDef Matrix_methods[] = {
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
/*------------------PY_OBECT DEFINITION--------------------------*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: Python Object Definition
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
matrix_doc,
|
||||
".. class:: Matrix([rows])\n"
|
||||
@@ -3268,6 +3354,12 @@ PyTypeObject matrix_Type = {
|
||||
NULL, /*tp_del*/
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: C/API Constructors
|
||||
* \{ */
|
||||
|
||||
PyObject *Matrix_CreatePyObject(const float *mat,
|
||||
const ushort col_num,
|
||||
const ushort row_num,
|
||||
@@ -3380,6 +3472,12 @@ PyObject *Matrix_CreatePyObject_alloc(float *mat,
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix Type: C/API Parse Utilities
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Use with PyArg_ParseTuple's "O&" formatting.
|
||||
*/
|
||||
@@ -3460,8 +3558,11 @@ int Matrix_Parse4x4(PyObject *o, void *p)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* special type for alternate access */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix-Access Type: Struct & Internal Functions
|
||||
* \{ */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD /* Required Python macro. */
|
||||
@@ -3491,7 +3592,11 @@ static void MatrixAccess_dealloc(MatrixAccessObject *self)
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
/* sequence access */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix-Access Type: Sequence Protocol
|
||||
* \{ */
|
||||
|
||||
static int MatrixAccess_len(MatrixAccessObject *self)
|
||||
{
|
||||
@@ -3609,13 +3714,13 @@ static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item,
|
||||
|
||||
static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
|
||||
{
|
||||
/* Try get values from a collection */
|
||||
/* Try get values from a collection. */
|
||||
PyObject *ret;
|
||||
PyObject *iter = NULL;
|
||||
ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM);
|
||||
|
||||
/* we know this is a tuple so no need to PyIter_Check
|
||||
* otherwise it could be NULL (unlikely) if conversion failed */
|
||||
/* We know this is a tuple so no need to #PyIter_Check
|
||||
* otherwise it could be NULL (unlikely) if conversion failed. */
|
||||
if (ret) {
|
||||
iter = PyObject_GetIter(ret);
|
||||
Py_DECREF(ret);
|
||||
@@ -3630,6 +3735,12 @@ static PyMappingMethods MatrixAccess_AsMapping = {
|
||||
(objobjargproc)MatrixAccess_ass_subscript,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix-Access Type: Python Object Definition
|
||||
* \{ */
|
||||
|
||||
PyTypeObject matrix_access_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0) "MatrixAccess", /*tp_name*/
|
||||
sizeof(MatrixAccessObject), /*tp_basicsize*/
|
||||
@@ -3658,6 +3769,12 @@ PyTypeObject matrix_access_Type = {
|
||||
(getiterfunc)MatrixAccess_iter, /* getiterfunc tp_iter; */
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Matrix-Access Type: C/API Constructor
|
||||
* \{ */
|
||||
|
||||
static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
|
||||
{
|
||||
MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject,
|
||||
@@ -3671,5 +3788,4 @@ static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrix
|
||||
return (PyObject *)matrix_access;
|
||||
}
|
||||
|
||||
/* end special access
|
||||
* -------------------------------------------------------------------------- */
|
||||
/** \} */
|
||||
|
||||
@@ -45,7 +45,8 @@ typedef struct {
|
||||
* be stored in py_data) or be a wrapper for data allocated through
|
||||
* blender (stored in blend_data). This is an either/or struct not both */
|
||||
|
||||
/* prototypes */
|
||||
/* Prototypes. */
|
||||
|
||||
PyObject *Matrix_CreatePyObject(const float *mat,
|
||||
ushort col_num,
|
||||
ushort row_num,
|
||||
@@ -70,6 +71,7 @@ PyObject *Matrix_CreatePyObject_alloc(float *mat,
|
||||
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/* PyArg_ParseTuple's "O&" formatting helpers. */
|
||||
|
||||
int Matrix_ParseAny(PyObject *o, void *p);
|
||||
int Matrix_Parse2x2(PyObject *o, void *p);
|
||||
int Matrix_Parse3x3(PyObject *o, void *p);
|
||||
|
||||
@@ -26,9 +26,49 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle);
|
||||
static PyObject *Quaternion_copy(QuaternionObject *self);
|
||||
static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
|
||||
|
||||
/* -----------------------------METHODS------------------------------ */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities
|
||||
* \{ */
|
||||
|
||||
/* NOTE: BaseMath_ReadCallback must be called beforehand. */
|
||||
static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
|
||||
QuaternionObject *self)
|
||||
{
|
||||
PyObject *ret = Quaternion_copy(self);
|
||||
PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
|
||||
if (ret_dummy) {
|
||||
Py_DECREF(ret_dummy);
|
||||
return ret;
|
||||
}
|
||||
/* error */
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Axis vector suffers from precision errors, use this function to ensure. */
|
||||
static void quat__axis_angle_sanitize(float axis[3], float *angle)
|
||||
{
|
||||
if (axis) {
|
||||
if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
|
||||
axis[0] = 1.0f;
|
||||
axis[1] = 0.0f;
|
||||
axis[2] = 0.0f;
|
||||
}
|
||||
else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
|
||||
EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
|
||||
axis[0] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (angle) {
|
||||
if (!isfinite(*angle)) {
|
||||
*angle = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \note #BaseMath_ReadCallback must be called beforehand.
|
||||
*/
|
||||
static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
|
||||
{
|
||||
PyObject *ret;
|
||||
@@ -50,6 +90,72 @@ static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: `__new__` / `mathutils.Quaternion()`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *seq = NULL;
|
||||
double angle = 0.0f;
|
||||
float quat[QUAT_SIZE];
|
||||
unit_qt(quat);
|
||||
|
||||
if (kwds && PyDict_Size(kwds)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"mathutils.Quaternion(): "
|
||||
"takes no keyword args");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (PyTuple_GET_SIZE(args)) {
|
||||
case 0:
|
||||
break;
|
||||
case 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];
|
||||
if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
|
||||
return NULL;
|
||||
}
|
||||
angle = angle_wrap_rad(angle); /* clamp because of precision issues */
|
||||
axis_angle_to_quat(quat, axis, angle);
|
||||
break;
|
||||
/* PyArg_ParseTuple assures no more than 2 */
|
||||
}
|
||||
}
|
||||
return Quaternion_CreatePyObject(quat, type);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: To Euler
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_to_euler_doc,
|
||||
".. method:: to_euler(order, euler_compat)\n"
|
||||
"\n"
|
||||
@@ -114,6 +220,12 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
|
||||
return Euler_CreatePyObject(eul, order, NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: To Matrix
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_to_matrix_doc,
|
||||
".. method:: to_matrix()\n"
|
||||
"\n"
|
||||
@@ -133,6 +245,12 @@ static PyObject *Quaternion_to_matrix(QuaternionObject *self)
|
||||
return Matrix_CreatePyObject(mat, 3, 3, NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: To Axis/Angle
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
|
||||
".. method:: to_axis_angle()\n"
|
||||
"\n"
|
||||
@@ -163,6 +281,12 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: To Swing/Twist
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
|
||||
".. method:: to_swing_twist(axis)\n"
|
||||
"\n"
|
||||
@@ -207,6 +331,12 @@ static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axi
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: To Exponential Map
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Quaternion_to_exponential_map_doc,
|
||||
".. method:: to_exponential_map()\n"
|
||||
@@ -232,6 +362,12 @@ static PyObject *Quaternion_to_exponential_map(QuaternionObject *self)
|
||||
return Vector_CreatePyObject(expmap, 3, NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Cross Product
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_cross_doc,
|
||||
".. method:: cross(other)\n"
|
||||
"\n"
|
||||
@@ -259,6 +395,12 @@ static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
|
||||
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Dot Product
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_dot_doc,
|
||||
".. method:: dot(other)\n"
|
||||
"\n"
|
||||
@@ -285,6 +427,12 @@ static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
|
||||
return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Rotation Difference
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_rotation_difference_doc,
|
||||
".. function:: rotation_difference(other)\n"
|
||||
"\n"
|
||||
@@ -315,6 +463,12 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject
|
||||
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Spherical Interpolation (slerp)
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_slerp_doc,
|
||||
".. function:: slerp(other, factor)\n"
|
||||
"\n"
|
||||
@@ -360,6 +514,12 @@ static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
|
||||
return Quaternion_CreatePyObject(quat, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Rotate
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_rotate_doc,
|
||||
".. method:: rotate(other)\n"
|
||||
"\n"
|
||||
@@ -423,9 +583,15 @@ static PyObject *Quaternion_make_compatible(QuaternionObject *self, PyObject *va
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* ----------------------------Quaternion.normalize()---------------- */
|
||||
/* Normalize the quaternion. This may change the angle as well as the
|
||||
* rotation axis, as all of (w, x, y, z) are scaled. */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Normalize
|
||||
*
|
||||
* 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"
|
||||
@@ -453,6 +619,15 @@ static PyObject *Quaternion_normalized(QuaternionObject *self)
|
||||
return quat__apply_to_copy(Quaternion_normalize, self);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Invert
|
||||
*
|
||||
* 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_invert_doc,
|
||||
".. function:: invert()\n"
|
||||
"\n"
|
||||
@@ -480,6 +655,12 @@ static PyObject *Quaternion_inverted(QuaternionObject *self)
|
||||
return quat__apply_to_copy(Quaternion_invert, self);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Set Identity
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_identity_doc,
|
||||
".. function:: identity()\n"
|
||||
"\n"
|
||||
@@ -498,6 +679,12 @@ static PyObject *Quaternion_identity(QuaternionObject *self)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Negate
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_negate_doc,
|
||||
".. function:: negate()\n"
|
||||
"\n"
|
||||
@@ -516,6 +703,12 @@ static PyObject *Quaternion_negate(QuaternionObject *self)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Conjugate
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_conjugate_doc,
|
||||
".. function:: conjugate()\n"
|
||||
"\n"
|
||||
@@ -543,6 +736,12 @@ static PyObject *Quaternion_conjugated(QuaternionObject *self)
|
||||
return quat__apply_to_copy(Quaternion_conjugate, self);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Methods: Copy/Deep-Copy
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_copy_doc,
|
||||
".. function:: copy()\n"
|
||||
"\n"
|
||||
@@ -569,7 +768,12 @@ static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
|
||||
return Quaternion_copy(self);
|
||||
}
|
||||
|
||||
/* print the object to screen */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: `__repr__` & `__str__`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Quaternion_repr(QuaternionObject *self)
|
||||
{
|
||||
PyObject *ret, *tuple;
|
||||
@@ -608,6 +812,12 @@ static PyObject *Quaternion_str(QuaternionObject *self)
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Rich Compare
|
||||
* \{ */
|
||||
|
||||
static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
@@ -646,6 +856,12 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
|
||||
return Py_INCREF_RET(res);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Hash (`__hash__`)
|
||||
* \{ */
|
||||
|
||||
static Py_hash_t Quaternion_hash(QuaternionObject *self)
|
||||
{
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
@@ -659,15 +875,19 @@ static Py_hash_t Quaternion_hash(QuaternionObject *self)
|
||||
return mathutils_array_hash(self->quat, QUAT_SIZE);
|
||||
}
|
||||
|
||||
/* ---------------------SEQUENCE PROTOCOLS------------------------ */
|
||||
/* ----------------------------len(object)------------------------ */
|
||||
/* sequence length */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Sequence & Mapping Protocols Implementation
|
||||
* \{ */
|
||||
|
||||
/** Sequence length: `len(object)`. */
|
||||
static int Quaternion_len(QuaternionObject *UNUSED(self))
|
||||
{
|
||||
return QUAT_SIZE;
|
||||
}
|
||||
/* ----------------------------object[]--------------------------- */
|
||||
/* sequence accessor (get) */
|
||||
|
||||
/** Sequence accessor (get): `x = object[i]`. */
|
||||
static PyObject *Quaternion_item(QuaternionObject *self, int i)
|
||||
{
|
||||
if (i < 0) {
|
||||
@@ -687,8 +907,8 @@ static PyObject *Quaternion_item(QuaternionObject *self, int i)
|
||||
|
||||
return PyFloat_FromDouble(self->quat[i]);
|
||||
}
|
||||
/* ----------------------------object[]------------------------- */
|
||||
/* sequence accessor (set) */
|
||||
|
||||
/** Sequence accessor (set): `object[i] = x`. */
|
||||
static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
|
||||
{
|
||||
float f;
|
||||
@@ -724,8 +944,8 @@ static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ----------------------------object[z:y]------------------------ */
|
||||
/* sequence slice (get) */
|
||||
|
||||
/** Sequence slice accessor (get): `x = object[i:j]`. */
|
||||
static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
|
||||
{
|
||||
PyObject *tuple;
|
||||
@@ -749,8 +969,8 @@ static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
|
||||
|
||||
return tuple;
|
||||
}
|
||||
/* ----------------------------object[z:y]------------------------ */
|
||||
/* sequence slice (set) */
|
||||
|
||||
/** Sequence slice accessor (set): `object[i:j] = x`. */
|
||||
static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
|
||||
{
|
||||
int i, size;
|
||||
@@ -779,7 +999,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parsed well - now set in vector */
|
||||
/* Parsed well, now set in vector. */
|
||||
for (i = 0; i < size; i++) {
|
||||
self->quat[begin + i] = quat[i];
|
||||
}
|
||||
@@ -788,6 +1008,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (get): `x = object[...]`. */
|
||||
static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -824,6 +1045,7 @@ static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (set): `object[...] = x`. */
|
||||
static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -856,9 +1078,13 @@ static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyOb
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------NUMERIC PROTOCOLS---------------------- */
|
||||
/* ------------------------obj + obj------------------------------ */
|
||||
/* addition */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Numeric Protocol Implementation
|
||||
* \{ */
|
||||
|
||||
/** Addition: `object + object`. */
|
||||
static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
|
||||
{
|
||||
float quat[QUAT_SIZE];
|
||||
@@ -882,8 +1108,8 @@ static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
|
||||
add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
|
||||
return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
|
||||
}
|
||||
/* ------------------------obj - obj------------------------------ */
|
||||
/* subtraction */
|
||||
|
||||
/** Subtraction: `object - object`. */
|
||||
static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
|
||||
{
|
||||
int x;
|
||||
@@ -921,8 +1147,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
|
||||
return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
|
||||
}
|
||||
|
||||
/*------------------------obj * obj------------------------------
|
||||
* multiplication */
|
||||
/** Multiplication (element-wise or scalar): `object * object`. */
|
||||
static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
|
||||
{
|
||||
float scalar;
|
||||
@@ -965,8 +1190,8 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
|
||||
Py_TYPE(q2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
/*------------------------obj *= obj------------------------------
|
||||
* in-place multiplication */
|
||||
|
||||
/** Multiplication in-place (element-wise or scalar): `object *= object`. */
|
||||
static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
|
||||
{
|
||||
float scalar;
|
||||
@@ -1005,8 +1230,8 @@ static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
|
||||
Py_INCREF(q1);
|
||||
return q1;
|
||||
}
|
||||
/*------------------------obj @ obj------------------------------
|
||||
* quaternion multiplication */
|
||||
|
||||
/** Multiplication (quaternion multiply): `object @ object`. */
|
||||
static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
|
||||
{
|
||||
float quat[QUAT_SIZE];
|
||||
@@ -1060,8 +1285,8 @@ static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
|
||||
Py_TYPE(q2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
/*------------------------obj @= obj------------------------------
|
||||
* in-place quaternion multiplication */
|
||||
|
||||
/** Multiplication in-place (quaternion multiply): `object @= object`. */
|
||||
static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
|
||||
{
|
||||
float quat[QUAT_SIZE];
|
||||
@@ -1098,8 +1323,7 @@ static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
|
||||
return q1;
|
||||
}
|
||||
|
||||
/* -obj
|
||||
* Returns the negative of this object. */
|
||||
/** Negative (returns the negative of this object): `-object`. */
|
||||
static PyObject *Quaternion_neg(QuaternionObject *self)
|
||||
{
|
||||
float tquat[QUAT_SIZE];
|
||||
@@ -1112,18 +1336,23 @@ static PyObject *Quaternion_neg(QuaternionObject *self)
|
||||
return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/* -----------------PROTOCOL DECLARATIONS-------------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Protocol Declarations
|
||||
* \{ */
|
||||
|
||||
static PySequenceMethods Quaternion_SeqMethods = {
|
||||
(lenfunc)Quaternion_len, /* sq_length */
|
||||
(binaryfunc)NULL, /* sq_concat */
|
||||
(ssizeargfunc)NULL, /* sq_repeat */
|
||||
(ssizeargfunc)Quaternion_item, /* sq_item */
|
||||
(ssizessizeargfunc)NULL, /* sq_slice, deprecated */
|
||||
(ssizeobjargproc)Quaternion_ass_item, /* sq_ass_item */
|
||||
(ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
|
||||
(objobjproc)NULL, /* sq_contains */
|
||||
(binaryfunc)NULL, /* sq_inplace_concat */
|
||||
(ssizeargfunc)NULL, /* sq_inplace_repeat */
|
||||
(lenfunc)Quaternion_len, /*sq_length*/
|
||||
(binaryfunc)NULL, /*sq_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_repeat*/
|
||||
(ssizeargfunc)Quaternion_item, /*sq_item*/
|
||||
(ssizessizeargfunc)NULL, /*sq_slice(deprecated)*/
|
||||
(ssizeobjargproc)Quaternion_ass_item, /*sq_ass_item*/
|
||||
(ssizessizeobjargproc)NULL, /*sq_ass_slice(deprecated)*/
|
||||
(objobjproc)NULL, /*sq_contains*/
|
||||
(binaryfunc)NULL, /*sq_inplace_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_inplace_repeat*/
|
||||
};
|
||||
|
||||
static PyMappingMethods Quaternion_AsMapping = {
|
||||
@@ -1152,25 +1381,31 @@ static PyNumberMethods Quaternion_NumMethods = {
|
||||
NULL, /*nb_int*/
|
||||
NULL, /*nb_reserved*/
|
||||
NULL, /*nb_float*/
|
||||
NULL, /* nb_inplace_add */
|
||||
NULL, /* nb_inplace_subtract */
|
||||
(binaryfunc)Quaternion_imul, /* nb_inplace_multiply */
|
||||
NULL, /* nb_inplace_remainder */
|
||||
NULL, /* nb_inplace_power */
|
||||
NULL, /* nb_inplace_lshift */
|
||||
NULL, /* nb_inplace_rshift */
|
||||
NULL, /* nb_inplace_and */
|
||||
NULL, /* nb_inplace_xor */
|
||||
NULL, /* nb_inplace_or */
|
||||
NULL, /* nb_floor_divide */
|
||||
NULL, /* nb_true_divide */
|
||||
NULL, /* nb_inplace_floor_divide */
|
||||
NULL, /* nb_inplace_true_divide */
|
||||
NULL, /* nb_index */
|
||||
(binaryfunc)Quaternion_matmul, /* nb_matrix_multiply */
|
||||
(binaryfunc)Quaternion_imatmul, /* nb_inplace_matrix_multiply */
|
||||
NULL, /*nb_inplace_add*/
|
||||
NULL, /*nb_inplace_subtract*/
|
||||
(binaryfunc)Quaternion_imul, /*nb_inplace_multiply*/
|
||||
NULL, /*nb_inplace_remainder*/
|
||||
NULL, /*nb_inplace_power*/
|
||||
NULL, /*nb_inplace_lshift*/
|
||||
NULL, /*nb_inplace_rshift*/
|
||||
NULL, /*nb_inplace_and*/
|
||||
NULL, /*nb_inplace_xor*/
|
||||
NULL, /*nb_inplace_or*/
|
||||
NULL, /*nb_floor_divide*/
|
||||
NULL, /*nb_true_divide*/
|
||||
NULL, /*nb_inplace_floor_divide*/
|
||||
NULL, /*nb_inplace_true_divide*/
|
||||
NULL, /*nb_index*/
|
||||
(binaryfunc)Quaternion_matmul, /*nb_matrix_multiply*/
|
||||
(binaryfunc)Quaternion_imatmul, /*nb_inplace_matrix_multiply*/
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Get/Set Item Implementation
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Quaternion_axis_doc, "Quaternion axis value.\n\n:type: float");
|
||||
static PyObject *Quaternion_axis_get(QuaternionObject *self, void *type)
|
||||
{
|
||||
@@ -1300,98 +1535,69 @@ static int Quaternion_axis_vector_set(QuaternionObject *self,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------mathutils.Quaternion() -------------- */
|
||||
static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *seq = NULL;
|
||||
double angle = 0.0f;
|
||||
float quat[QUAT_SIZE];
|
||||
unit_qt(quat);
|
||||
/** \} */
|
||||
|
||||
if (kwds && PyDict_Size(kwds)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"mathutils.Quaternion(): "
|
||||
"takes no keyword args");
|
||||
return NULL;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Get/Set Item Definitions
|
||||
* \{ */
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
|
||||
return NULL;
|
||||
}
|
||||
static PyGetSetDef Quaternion_getseters[] = {
|
||||
{"w",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)0},
|
||||
{"x",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)1},
|
||||
{"y",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)2},
|
||||
{"z",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)3},
|
||||
{"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
|
||||
{"angle",
|
||||
(getter)Quaternion_angle_get,
|
||||
(setter)Quaternion_angle_set,
|
||||
Quaternion_angle_doc,
|
||||
NULL},
|
||||
{"axis",
|
||||
(getter)Quaternion_axis_vector_get,
|
||||
(setter)Quaternion_axis_vector_set,
|
||||
Quaternion_axis_vector_doc,
|
||||
NULL},
|
||||
{"is_wrapped",
|
||||
(getter)BaseMathObject_is_wrapped_get,
|
||||
(setter)NULL,
|
||||
BaseMathObject_is_wrapped_doc,
|
||||
NULL},
|
||||
{"is_frozen",
|
||||
(getter)BaseMathObject_is_frozen_get,
|
||||
(setter)NULL,
|
||||
BaseMathObject_is_frozen_doc,
|
||||
NULL},
|
||||
{"is_valid",
|
||||
(getter)BaseMathObject_is_valid_get,
|
||||
(setter)NULL,
|
||||
BaseMathObject_is_valid_doc,
|
||||
NULL},
|
||||
{"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
switch (PyTuple_GET_SIZE(args)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1: {
|
||||
int size;
|
||||
/** \} */
|
||||
|
||||
if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
|
||||
-1) {
|
||||
return NULL;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Method Definitions
|
||||
* \{ */
|
||||
|
||||
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];
|
||||
if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
|
||||
return NULL;
|
||||
}
|
||||
angle = angle_wrap_rad(angle); /* clamp because of precision issues */
|
||||
axis_angle_to_quat(quat, axis, angle);
|
||||
break;
|
||||
/* PyArg_ParseTuple assures no more than 2 */
|
||||
}
|
||||
}
|
||||
return Quaternion_CreatePyObject(quat, type);
|
||||
}
|
||||
|
||||
static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
|
||||
QuaternionObject *self)
|
||||
{
|
||||
PyObject *ret = Quaternion_copy(self);
|
||||
PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
|
||||
if (ret_dummy) {
|
||||
Py_DECREF(ret_dummy);
|
||||
return ret;
|
||||
}
|
||||
/* error */
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* axis vector suffers from precision errors, use this function to ensure */
|
||||
static void quat__axis_angle_sanitize(float axis[3], float *angle)
|
||||
{
|
||||
if (axis) {
|
||||
if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
|
||||
axis[0] = 1.0f;
|
||||
axis[1] = 0.0f;
|
||||
axis[2] = 0.0f;
|
||||
}
|
||||
else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
|
||||
EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
|
||||
axis[0] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (angle) {
|
||||
if (!isfinite(*angle)) {
|
||||
*angle = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------METHOD DEFINITIONS ---------------------- */
|
||||
static struct PyMethodDef Quaternion_methods[] = {
|
||||
/* In place only. */
|
||||
{"identity", (PyCFunction)Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
|
||||
@@ -1446,61 +1652,12 @@ static struct PyMethodDef Quaternion_methods[] = {
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python attributes get/set structure: */
|
||||
/*****************************************************************************/
|
||||
static PyGetSetDef Quaternion_getseters[] = {
|
||||
{"w",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)0},
|
||||
{"x",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)1},
|
||||
{"y",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)2},
|
||||
{"z",
|
||||
(getter)Quaternion_axis_get,
|
||||
(setter)Quaternion_axis_set,
|
||||
Quaternion_axis_doc,
|
||||
(void *)3},
|
||||
{"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
|
||||
{"angle",
|
||||
(getter)Quaternion_angle_get,
|
||||
(setter)Quaternion_angle_set,
|
||||
Quaternion_angle_doc,
|
||||
NULL},
|
||||
{"axis",
|
||||
(getter)Quaternion_axis_vector_get,
|
||||
(setter)Quaternion_axis_vector_set,
|
||||
Quaternion_axis_vector_doc,
|
||||
NULL},
|
||||
{"is_wrapped",
|
||||
(getter)BaseMathObject_is_wrapped_get,
|
||||
(setter)NULL,
|
||||
BaseMathObject_is_wrapped_doc,
|
||||
NULL},
|
||||
{"is_frozen",
|
||||
(getter)BaseMathObject_is_frozen_get,
|
||||
(setter)NULL,
|
||||
BaseMathObject_is_frozen_doc,
|
||||
NULL},
|
||||
{"is_valid",
|
||||
(getter)BaseMathObject_is_valid_get,
|
||||
(setter)NULL,
|
||||
BaseMathObject_is_valid_doc,
|
||||
NULL},
|
||||
{"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
};
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: Python Object Definition
|
||||
* \{ */
|
||||
|
||||
/* ------------------PY_OBECT DEFINITION-------------------------- */
|
||||
PyDoc_STRVAR(quaternion_doc,
|
||||
".. class:: Quaternion([seq, [angle]])\n"
|
||||
"\n"
|
||||
@@ -1577,6 +1734,12 @@ PyTypeObject quaternion_Type = {
|
||||
NULL, /* tp_del */
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Quaternion Type: C/API Constructors
|
||||
* \{ */
|
||||
|
||||
PyObject *Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
|
||||
{
|
||||
QuaternionObject *self;
|
||||
@@ -1643,3 +1806,5 @@ PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar c
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -20,7 +20,8 @@ typedef struct {
|
||||
* be stored in py_data) or be a wrapper for data allocated through
|
||||
* blender (stored in blend_data). This is an either/or struct not both */
|
||||
|
||||
/* prototypes */
|
||||
/* Prototypes. */
|
||||
|
||||
PyObject *Quaternion_CreatePyObject(const float quat[4],
|
||||
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
|
||||
PyObject *Quaternion_CreatePyObject_wrap(float quat[4],
|
||||
|
||||
@@ -24,19 +24,108 @@
|
||||
*/
|
||||
#define MAX_DIMENSIONS 4
|
||||
|
||||
/* Swizzle axes get packed into a single value that is used as a closure. Each
|
||||
/**
|
||||
* Swizzle axes get packed into a single value that is used as a closure. Each
|
||||
* axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is
|
||||
* used as a sentinel: if it is unset, the axis is not valid. */
|
||||
* used as a sentinel: if it is unset, the axis is not valid.
|
||||
*/
|
||||
#define SWIZZLE_BITS_PER_AXIS 3
|
||||
#define SWIZZLE_VALID_AXIS 0x4
|
||||
#define SWIZZLE_AXIS 0x3
|
||||
|
||||
static PyObject *Vector_copy(VectorObject *self);
|
||||
static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args);
|
||||
static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Row vector multiplication - (Vector * Matrix)
|
||||
* <pre>
|
||||
* [x][y][z] * [1][4][7]
|
||||
* [2][5][8]
|
||||
* [3][6][9]
|
||||
* </pre>
|
||||
* \note vector/matrix multiplication is not commutative.
|
||||
*/
|
||||
static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS],
|
||||
VectorObject *vec,
|
||||
MatrixObject *mat);
|
||||
MatrixObject *mat)
|
||||
{
|
||||
float vec_cpy[MAX_DIMENSIONS];
|
||||
int row, col, z = 0, vec_num = vec->vec_num;
|
||||
|
||||
if (mat->row_num != vec_num) {
|
||||
if (mat->row_num == 4 && vec_num == 3) {
|
||||
vec_cpy[3] = 1.0f;
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"vector * matrix: matrix column size "
|
||||
"and the vector size must be the same");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(vec_cpy, vec->vec, vec_num * sizeof(float));
|
||||
|
||||
r_vec[3] = 1.0f;
|
||||
/* Multiplication. */
|
||||
for (col = 0; col < mat->col_num; col++) {
|
||||
double dot = 0.0;
|
||||
for (row = 0; row < mat->row_num; row++) {
|
||||
dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[row]);
|
||||
}
|
||||
r_vec[z++] = (float)dot;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
|
||||
{
|
||||
PyObject *ret = Vector_copy(self);
|
||||
PyObject *ret_dummy = vec_func((VectorObject *)ret);
|
||||
if (ret_dummy) {
|
||||
Py_DECREF(ret_dummy);
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
/* error */
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \note #BaseMath_ReadCallback must be called beforehand. */
|
||||
static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits)
|
||||
{
|
||||
PyObject *ret;
|
||||
int i;
|
||||
|
||||
ret = PyTuple_New(self->vec_num);
|
||||
|
||||
if (ndigits >= 0) {
|
||||
for (i = 0; i < self->vec_num; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < self->vec_num; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: `__new__` / `mathutils.Vector()`
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Supports 2D, 3D, and 4D vector objects both int and float values
|
||||
@@ -82,20 +171,12 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
return Vector_CreatePyObject_alloc(vec, vec_num, type);
|
||||
}
|
||||
|
||||
static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
|
||||
{
|
||||
PyObject *ret = Vector_copy(self);
|
||||
PyObject *ret_dummy = vec_func((VectorObject *)ret);
|
||||
if (ret_dummy) {
|
||||
Py_DECREF(ret_dummy);
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
/* error */
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Class Methods
|
||||
* \{ */
|
||||
|
||||
/*-----------------------CLASS-METHODS----------------------------*/
|
||||
PyDoc_STRVAR(C_Vector_Fill_doc,
|
||||
".. classmethod:: Fill(size, fill=0.0)\n"
|
||||
"\n"
|
||||
@@ -311,7 +392,12 @@ static PyObject *C_Vector_Repeat(PyObject *cls, PyObject *args)
|
||||
return Vector_CreatePyObject_alloc(vec, vec_num, (PyTypeObject *)cls);
|
||||
}
|
||||
|
||||
/*-----------------------------METHODS---------------------------- */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Zero
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_zero_doc,
|
||||
".. method:: zero()\n"
|
||||
"\n"
|
||||
@@ -331,6 +417,12 @@ static PyObject *Vector_zero(VectorObject *self)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Normalize
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_normalize_doc,
|
||||
".. method:: normalize()\n"
|
||||
"\n"
|
||||
@@ -364,6 +456,12 @@ static PyObject *Vector_normalized(VectorObject *self)
|
||||
return vec__apply_to_copy(Vector_normalize, self);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Resize
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_resize_doc,
|
||||
".. method:: resize(size=3)\n"
|
||||
"\n"
|
||||
@@ -553,6 +651,13 @@ static PyObject *Vector_resize_4d(VectorObject *self)
|
||||
self->vec_num = 4;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: To N-dimensions
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_to_2d_doc,
|
||||
".. method:: to_2d()\n"
|
||||
"\n"
|
||||
@@ -605,6 +710,12 @@ static PyObject *Vector_to_4d(VectorObject *self)
|
||||
return Vector_CreatePyObject(tvec, 4, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: To Tuple
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_to_tuple_doc,
|
||||
".. method:: to_tuple(precision=-1)\n"
|
||||
"\n"
|
||||
@@ -614,28 +725,6 @@ PyDoc_STRVAR(Vector_to_tuple_doc,
|
||||
" :type precision: int\n"
|
||||
" :return: the values of the vector rounded by *precision*\n"
|
||||
" :rtype: tuple\n");
|
||||
/* NOTE: BaseMath_ReadCallback must be called beforehand. */
|
||||
static PyObject *Vector_to_tuple_ex(VectorObject *self, int ndigits)
|
||||
{
|
||||
PyObject *ret;
|
||||
int i;
|
||||
|
||||
ret = PyTuple_New(self->vec_num);
|
||||
|
||||
if (ndigits >= 0) {
|
||||
for (i = 0; i < self->vec_num; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < self->vec_num; i++) {
|
||||
PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
|
||||
{
|
||||
int ndigits = 0;
|
||||
@@ -662,6 +751,12 @@ static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
|
||||
return Vector_to_tuple_ex(self, ndigits);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: To Track Quaternion
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_to_track_quat_doc,
|
||||
".. method:: to_track_quat(track, up)\n"
|
||||
"\n"
|
||||
@@ -781,6 +876,12 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
|
||||
return Quaternion_CreatePyObject(quat, NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Orthogonal
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Vector_orthogonal_doc,
|
||||
".. method:: orthogonal()\n"
|
||||
@@ -816,12 +917,15 @@ static PyObject *Vector_orthogonal(VectorObject *self)
|
||||
return Vector_CreatePyObject(vec, self->vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/**
|
||||
* Vector.reflect(mirror): return a reflected vector on the mirror normal.
|
||||
* <pre>
|
||||
* vec - ((2 * dot(vec, mirror)) * mirror)
|
||||
* </pre>
|
||||
*/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Reflect
|
||||
*
|
||||
* `Vector.reflect(mirror)`: return a reflected vector on the mirror normal:
|
||||
* `vec - ((2 * dot(vec, mirror)) * mirror)`.
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_reflect_doc,
|
||||
".. method:: reflect(mirror)\n"
|
||||
"\n"
|
||||
@@ -866,6 +970,12 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
|
||||
return Vector_CreatePyObject(reflect, self->vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Cross Product
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_cross_doc,
|
||||
".. method:: cross(other)\n"
|
||||
"\n"
|
||||
@@ -908,6 +1018,12 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Dot Product
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_dot_doc,
|
||||
".. method:: dot(other)\n"
|
||||
"\n"
|
||||
@@ -936,6 +1052,12 @@ static PyObject *Vector_dot(VectorObject *self, PyObject *value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Angle
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Vector_angle_doc,
|
||||
".. function:: angle(other, fallback=None)\n"
|
||||
@@ -1001,6 +1123,12 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args)
|
||||
return PyFloat_FromDouble(saacos(dot / (sqrt(dot_self) * sqrt(dot_other))));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Angle Signed
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Vector_angle_signed_doc,
|
||||
".. function:: angle_signed(other, fallback)\n"
|
||||
@@ -1055,6 +1183,12 @@ static PyObject *Vector_angle_signed(VectorObject *self, PyObject *args)
|
||||
return PyFloat_FromDouble(angle_signed_v2v2(self->vec, tvec));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Rotation Difference
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_rotation_difference_doc,
|
||||
".. function:: rotation_difference(other)\n"
|
||||
"\n"
|
||||
@@ -1096,6 +1230,12 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value)
|
||||
return Quaternion_CreatePyObject(quat, NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Project
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_project_doc,
|
||||
".. function:: project(other)\n"
|
||||
"\n"
|
||||
@@ -1134,6 +1274,12 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
|
||||
return Vector_CreatePyObject_alloc(tvec, vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Linear Interpolation
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_lerp_doc,
|
||||
".. function:: lerp(other, factor)\n"
|
||||
"\n"
|
||||
@@ -1170,6 +1316,12 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
|
||||
return Vector_CreatePyObject_alloc(tvec, vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Spherical Interpolation
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_slerp_doc,
|
||||
".. function:: slerp(other, factor, fallback=None)\n"
|
||||
"\n"
|
||||
@@ -1256,6 +1408,12 @@ static PyObject *Vector_slerp(VectorObject *self, PyObject *args)
|
||||
return Vector_CreatePyObject(ret_vec, vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Rotate
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(
|
||||
Vector_rotate_doc,
|
||||
".. function:: rotate(other)\n"
|
||||
@@ -1297,6 +1455,34 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Negate
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_negate_doc,
|
||||
".. method:: negate()\n"
|
||||
"\n"
|
||||
" Set all values to their negative.\n");
|
||||
static PyObject *Vector_negate(VectorObject *self)
|
||||
{
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
negate_vn(self->vec, self->vec_num);
|
||||
|
||||
(void)BaseMath_WriteCallback(self); /* already checked for error */
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Methods: Copy/Deep-Copy
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(Vector_copy_doc,
|
||||
".. function:: copy()\n"
|
||||
"\n"
|
||||
@@ -1323,6 +1509,12 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args)
|
||||
return Vector_copy(self);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: `__repr__` & `__str__`
|
||||
* \{ */
|
||||
|
||||
static PyObject *Vector_repr(VectorObject *self)
|
||||
{
|
||||
PyObject *ret, *tuple;
|
||||
@@ -1362,644 +1554,12 @@ static PyObject *Vector_str(VectorObject *self)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sequence Protocol */
|
||||
/* sequence length len(vector) */
|
||||
static int Vector_len(VectorObject *self)
|
||||
{
|
||||
return self->vec_num;
|
||||
}
|
||||
/* sequence accessor (get): vector[index] */
|
||||
static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_attr)
|
||||
{
|
||||
if (i < 0) {
|
||||
i = self->vec_num - i;
|
||||
}
|
||||
/** \} */
|
||||
|
||||
if (i < 0 || i >= self->vec_num) {
|
||||
if (is_attr) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector.%c: unavailable on %dd vector",
|
||||
*(((const char *)"xyzw") + i),
|
||||
self->vec_num);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_IndexError, "vector[index]: out of range");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Rich Compare
|
||||
* \{ */
|
||||
|
||||
if (BaseMath_ReadIndexCallback(self, i) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyFloat_FromDouble(self->vec[i]);
|
||||
}
|
||||
|
||||
static PyObject *Vector_item(VectorObject *self, int i)
|
||||
{
|
||||
return vector_item_internal(self, i, false);
|
||||
}
|
||||
/* sequence accessor (set): vector[index] = value */
|
||||
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: "
|
||||
"assigned value not a number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
i = self->vec_num - i;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= self->vec_num) {
|
||||
if (is_attr) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector.%c = x: unavailable on %dd vector",
|
||||
*(((const char *)"xyzw") + i),
|
||||
self->vec_num);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_IndexError,
|
||||
"vector[index] = x: "
|
||||
"assignment index out of range");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
self->vec[i] = scalar;
|
||||
|
||||
if (BaseMath_WriteIndexCallback(self, i) == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Vector_ass_item(VectorObject *self, int i, PyObject *value)
|
||||
{
|
||||
return vector_ass_item_internal(self, i, value, false);
|
||||
}
|
||||
|
||||
/* sequence slice (get): vector[a:b] */
|
||||
static PyObject *Vector_slice(VectorObject *self, int begin, int end)
|
||||
{
|
||||
PyObject *tuple;
|
||||
int count;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CLAMP(begin, 0, self->vec_num);
|
||||
if (end < 0) {
|
||||
end = self->vec_num + end + 1;
|
||||
}
|
||||
CLAMP(end, 0, self->vec_num);
|
||||
begin = MIN2(begin, end);
|
||||
|
||||
tuple = PyTuple_New(end - begin);
|
||||
for (count = begin; count < end; count++) {
|
||||
PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->vec[count]));
|
||||
}
|
||||
|
||||
return tuple;
|
||||
}
|
||||
/* sequence slice (set): vector[a:b] = value */
|
||||
static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq)
|
||||
{
|
||||
int vec_num = 0;
|
||||
float *vec = NULL;
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CLAMP(begin, 0, self->vec_num);
|
||||
CLAMP(end, 0, self->vec_num);
|
||||
begin = MIN2(begin, end);
|
||||
|
||||
vec_num = (end - begin);
|
||||
if (mathutils_array_parse_alloc(&vec, vec_num, seq, "vector[begin:end] = [...]") == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec[:] = seq: "
|
||||
"problem allocating pointer space");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parsed well - now set in vector. */
|
||||
memcpy(self->vec + begin, vec, vec_num * sizeof(float));
|
||||
|
||||
PyMem_Free(vec);
|
||||
|
||||
if (BaseMath_WriteCallback(self) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Numeric Protocols */
|
||||
/* addition: obj + obj */
|
||||
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float *vec = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector addition: (%s + %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* VECTOR + VECTOR. */
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector addition: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* addition in-place: obj += obj */
|
||||
static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector addition: (%s += %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector addition: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_vn_vn(vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/* subtraction: obj - obj */
|
||||
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float *vec;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector subtraction: (%s - %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector subtraction: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* subtraction in-place: obj -= obj */
|
||||
static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector subtraction: (%s -= %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector subtraction: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub_vn_vn(vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/*------------------------obj * obj------------------------------
|
||||
* multiplication */
|
||||
|
||||
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
|
||||
{
|
||||
float vec_cpy[MAX_DIMENSIONS];
|
||||
int row, col, z = 0;
|
||||
|
||||
if (mat->col_num != vec->vec_num) {
|
||||
if (mat->col_num == 4 && vec->vec_num == 3) {
|
||||
vec_cpy[3] = 1.0f;
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"matrix * vector: "
|
||||
"len(matrix.col) and len(vector) must be the same, "
|
||||
"except for 4x4 matrix * 3D vector.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vec_cpy, vec->vec, vec->vec_num * sizeof(float));
|
||||
|
||||
r_vec[3] = 1.0f;
|
||||
|
||||
for (row = 0; row < mat->row_num; row++) {
|
||||
double dot = 0.0f;
|
||||
for (col = 0; col < mat->col_num; col++) {
|
||||
dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[col]);
|
||||
}
|
||||
r_vec[z++] = (float)dot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
|
||||
{
|
||||
float *tvec = PyMem_Malloc(vec->vec_num * sizeof(float));
|
||||
if (tvec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec * float: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vn_fl(tvec, vec->vec, vec->vec_num, scalar);
|
||||
return Vector_CreatePyObject_alloc(tvec, vec->vec_num, Py_TYPE(vec));
|
||||
}
|
||||
|
||||
static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
|
||||
{
|
||||
float *tvec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
if (tvec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec * vec: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vnvn(tvec, vec1->vec, vec2->vec, vec1->vec_num);
|
||||
return Vector_CreatePyObject_alloc(tvec, vec1->vec_num, Py_TYPE(vec1));
|
||||
}
|
||||
|
||||
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float scalar;
|
||||
|
||||
if (VectorObject_Check(v1)) {
|
||||
vec1 = (VectorObject *)v1;
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (VectorObject_Check(v2)) {
|
||||
vec2 = (VectorObject *)v2;
|
||||
if (BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Intentionally don't support (Quaternion) here, uses reverse order instead. */
|
||||
|
||||
/* make sure v1 is always the vector */
|
||||
if (vec1 && vec2) {
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector multiplication: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* element-wise product */
|
||||
return vector_mul_vec(vec1, vec2);
|
||||
}
|
||||
if (vec1) {
|
||||
if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */
|
||||
return vector_mul_float(vec1, scalar);
|
||||
}
|
||||
}
|
||||
else if (vec2) {
|
||||
if (((scalar = PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred()) == 0) { /* FLOAT * VEC */
|
||||
return vector_mul_float(vec2, scalar);
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Element-wise multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* multiplication in-place: obj *= obj */
|
||||
static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float scalar;
|
||||
|
||||
if (VectorObject_Check(v1)) {
|
||||
vec1 = (VectorObject *)v1;
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (VectorObject_Check(v2)) {
|
||||
vec2 = (VectorObject *)v2;
|
||||
if (BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Intentionally don't support (Quaternion, Matrix) here, uses reverse order instead. */
|
||||
|
||||
if (vec1 && vec2) {
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector multiplication: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Element-wise product in-place. */
|
||||
mul_vn_vn(vec1->vec, vec2->vec, vec1->vec_num);
|
||||
}
|
||||
else if (vec1 && (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) ==
|
||||
0)) { /* VEC *= FLOAT */
|
||||
mul_vn_fl(vec1->vec, vec1->vec_num, scalar);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"In place element-wise multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
int vec_num;
|
||||
|
||||
if (VectorObject_Check(v1)) {
|
||||
vec1 = (VectorObject *)v1;
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (VectorObject_Check(v2)) {
|
||||
vec2 = (VectorObject *)v2;
|
||||
if (BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Intentionally don't support (Quaternion) here, uses reverse order instead. */
|
||||
|
||||
/* make sure v1 is always the vector */
|
||||
if (vec1 && vec2) {
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector multiplication: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Dot product. */
|
||||
return PyFloat_FromDouble(dot_vn_vn(vec1->vec, vec2->vec, vec1->vec_num));
|
||||
}
|
||||
if (vec1) {
|
||||
if (MatrixObject_Check(v2)) {
|
||||
/* VEC @ MATRIX */
|
||||
float tvec[MAX_DIMENSIONS];
|
||||
|
||||
if (BaseMath_ReadCallback((MatrixObject *)v2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
if (row_vector_multiplication(tvec, vec1, (MatrixObject *)v2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (((MatrixObject *)v2)->row_num == 4 && vec1->vec_num == 3) {
|
||||
vec_num = 3;
|
||||
}
|
||||
else {
|
||||
vec_num = ((MatrixObject *)v2)->col_num;
|
||||
}
|
||||
|
||||
return Vector_CreatePyObject(tvec, vec_num, Py_TYPE(vec1));
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Vector multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"In place vector multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* divide: obj / obj */
|
||||
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
float *vec = NULL, scalar;
|
||||
VectorObject *vec1 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1)) { /* not a vector */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector division: "
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1; /* vector */
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) {
|
||||
/* parsed item not a number */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector division: "
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (scalar == 0.0f) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError,
|
||||
"Vector division: "
|
||||
"divide by zero error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec / value: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vn_fl(vec, vec1->vec, vec1->vec_num, 1.0f / scalar);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/* divide in-place: obj /= obj */
|
||||
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
float scalar;
|
||||
VectorObject *vec1 = (VectorObject *)v1;
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) {
|
||||
/* parsed item not a number */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector division: "
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (scalar == 0.0f) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError,
|
||||
"Vector division: "
|
||||
"divide by zero error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_fl(vec1->vec, vec1->vec_num, 1.0f / scalar);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/* -obj
|
||||
* Returns the negative of this object. */
|
||||
static PyObject *Vector_neg(VectorObject *self)
|
||||
{
|
||||
float *tvec;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tvec = PyMem_Malloc(self->vec_num * sizeof(float));
|
||||
negate_vn_vn(tvec, self->vec, self->vec_num);
|
||||
return Vector_CreatePyObject_alloc(tvec, self->vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/*------------------------tp_richcmpr
|
||||
* returns -1 exception, 0 false, 1 true */
|
||||
static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
|
||||
{
|
||||
VectorObject *vecA = NULL, *vecB = NULL;
|
||||
@@ -2081,6 +1641,12 @@ static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int compa
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Hash (`__hash__`)
|
||||
* \{ */
|
||||
|
||||
static Py_hash_t Vector_hash(VectorObject *self)
|
||||
{
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
@@ -2094,20 +1660,162 @@ static Py_hash_t Vector_hash(VectorObject *self)
|
||||
return mathutils_array_hash(self->vec, self->vec_num);
|
||||
}
|
||||
|
||||
/*-----------------PROTCOL DECLARATIONS--------------------------*/
|
||||
static PySequenceMethods Vector_SeqMethods = {
|
||||
(lenfunc)Vector_len, /* sq_length */
|
||||
(binaryfunc)NULL, /* sq_concat */
|
||||
(ssizeargfunc)NULL, /* sq_repeat */
|
||||
(ssizeargfunc)Vector_item, /* sq_item */
|
||||
NULL, /* py3 deprecated slice func */
|
||||
(ssizeobjargproc)Vector_ass_item, /* sq_ass_item */
|
||||
NULL, /* py3 deprecated slice assign func */
|
||||
(objobjproc)NULL, /* sq_contains */
|
||||
(binaryfunc)NULL, /* sq_inplace_concat */
|
||||
(ssizeargfunc)NULL, /* sq_inplace_repeat */
|
||||
};
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Sequence & Mapping Protocols Implementation
|
||||
* \{ */
|
||||
|
||||
/** Sequence length: `len(object)`. */
|
||||
static int Vector_len(VectorObject *self)
|
||||
{
|
||||
return self->vec_num;
|
||||
}
|
||||
|
||||
static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_attr)
|
||||
{
|
||||
if (i < 0) {
|
||||
i = self->vec_num - i;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= self->vec_num) {
|
||||
if (is_attr) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector.%c: unavailable on %dd vector",
|
||||
*(((const char *)"xyzw") + i),
|
||||
self->vec_num);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_IndexError, "vector[index]: out of range");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadIndexCallback(self, i) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyFloat_FromDouble(self->vec[i]);
|
||||
}
|
||||
|
||||
/** Sequence accessor (get): `x = object[i]`. */
|
||||
static PyObject *Vector_item(VectorObject *self, int i)
|
||||
{
|
||||
return vector_item_internal(self, i, false);
|
||||
}
|
||||
|
||||
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: "
|
||||
"assigned value not a number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
i = self->vec_num - i;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= self->vec_num) {
|
||||
if (is_attr) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector.%c = x: unavailable on %dd vector",
|
||||
*(((const char *)"xyzw") + i),
|
||||
self->vec_num);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_IndexError,
|
||||
"vector[index] = x: "
|
||||
"assignment index out of range");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
self->vec[i] = scalar;
|
||||
|
||||
if (BaseMath_WriteIndexCallback(self, i) == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sequence accessor (set): `object[i] = x`. */
|
||||
static int Vector_ass_item(VectorObject *self, int i, PyObject *value)
|
||||
{
|
||||
return vector_ass_item_internal(self, i, value, false);
|
||||
}
|
||||
|
||||
/** Sequence slice accessor (get): `x = object[i:j]`. */
|
||||
static PyObject *Vector_slice(VectorObject *self, int begin, int end)
|
||||
{
|
||||
PyObject *tuple;
|
||||
int count;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CLAMP(begin, 0, self->vec_num);
|
||||
if (end < 0) {
|
||||
end = self->vec_num + end + 1;
|
||||
}
|
||||
CLAMP(end, 0, self->vec_num);
|
||||
begin = MIN2(begin, end);
|
||||
|
||||
tuple = PyTuple_New(end - begin);
|
||||
for (count = begin; count < end; count++) {
|
||||
PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->vec[count]));
|
||||
}
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
/** Sequence slice accessor (set): `object[i:j] = x`. */
|
||||
static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq)
|
||||
{
|
||||
int vec_num = 0;
|
||||
float *vec = NULL;
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(self) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CLAMP(begin, 0, self->vec_num);
|
||||
CLAMP(end, 0, self->vec_num);
|
||||
begin = MIN2(begin, end);
|
||||
|
||||
vec_num = (end - begin);
|
||||
if (mathutils_array_parse_alloc(&vec, vec_num, seq, "vector[begin:end] = [...]") == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec[:] = seq: "
|
||||
"problem allocating pointer space");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parsed well - now set in vector. */
|
||||
memcpy(self->vec + begin, vec, vec_num * sizeof(float));
|
||||
|
||||
PyMem_Free(vec);
|
||||
|
||||
if (BaseMath_WriteCallback(self) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (get): `x = object[...]`. */
|
||||
static PyObject *Vector_subscript(VectorObject *self, PyObject *item)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -2144,6 +1852,7 @@ static PyObject *Vector_subscript(VectorObject *self, PyObject *item)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Sequence generic subscript (set): `object[...] = x`. */
|
||||
static int Vector_ass_subscript(VectorObject *self, PyObject *item, PyObject *value)
|
||||
{
|
||||
if (PyIndex_Check(item)) {
|
||||
@@ -2176,6 +1885,520 @@ static int Vector_ass_subscript(VectorObject *self, PyObject *item, PyObject *va
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Numeric Protocol Implementation
|
||||
* \{ */
|
||||
|
||||
/** Addition: `object + object`. */
|
||||
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float *vec = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector addition: (%s + %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* VECTOR + VECTOR. */
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector addition: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/** Addition in-place: `object += object`. */
|
||||
static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector addition: (%s += %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector addition: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_vn_vn(vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/** Subtraction: `object - object`. */
|
||||
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float *vec;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector subtraction: (%s - %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector subtraction: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Vector(): "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/** Subtraction in-place: `object -= object`. */
|
||||
static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"Vector subtraction: (%s -= %s) "
|
||||
"invalid type for this operation",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1;
|
||||
vec2 = (VectorObject *)v2;
|
||||
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"Vector subtraction: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub_vn_vn(vec1->vec, vec2->vec, vec1->vec_num);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/* Multiply internal implementation `object * object`, `object *= object`. */
|
||||
|
||||
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
|
||||
{
|
||||
float vec_cpy[MAX_DIMENSIONS];
|
||||
int row, col, z = 0;
|
||||
|
||||
if (mat->col_num != vec->vec_num) {
|
||||
if (mat->col_num == 4 && vec->vec_num == 3) {
|
||||
vec_cpy[3] = 1.0f;
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"matrix * vector: "
|
||||
"len(matrix.col) and len(vector) must be the same, "
|
||||
"except for 4x4 matrix * 3D vector.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vec_cpy, vec->vec, vec->vec_num * sizeof(float));
|
||||
|
||||
r_vec[3] = 1.0f;
|
||||
|
||||
for (row = 0; row < mat->row_num; row++) {
|
||||
double dot = 0.0f;
|
||||
for (col = 0; col < mat->col_num; col++) {
|
||||
dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[col]);
|
||||
}
|
||||
r_vec[z++] = (float)dot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
|
||||
{
|
||||
float *tvec = PyMem_Malloc(vec->vec_num * sizeof(float));
|
||||
if (tvec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec * float: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vn_fl(tvec, vec->vec, vec->vec_num, scalar);
|
||||
return Vector_CreatePyObject_alloc(tvec, vec->vec_num, Py_TYPE(vec));
|
||||
}
|
||||
|
||||
static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
|
||||
{
|
||||
float *tvec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
if (tvec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec * vec: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vnvn(tvec, vec1->vec, vec2->vec, vec1->vec_num);
|
||||
return Vector_CreatePyObject_alloc(tvec, vec1->vec_num, Py_TYPE(vec1));
|
||||
}
|
||||
|
||||
/** Multiplication (element-wise or scalar): `object * object`. */
|
||||
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float scalar;
|
||||
|
||||
if (VectorObject_Check(v1)) {
|
||||
vec1 = (VectorObject *)v1;
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (VectorObject_Check(v2)) {
|
||||
vec2 = (VectorObject *)v2;
|
||||
if (BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Intentionally don't support (Quaternion) here, uses reverse order instead. */
|
||||
|
||||
/* make sure v1 is always the vector */
|
||||
if (vec1 && vec2) {
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector multiplication: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* element-wise product */
|
||||
return vector_mul_vec(vec1, vec2);
|
||||
}
|
||||
if (vec1) {
|
||||
if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */
|
||||
return vector_mul_float(vec1, scalar);
|
||||
}
|
||||
}
|
||||
else if (vec2) {
|
||||
if (((scalar = PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred()) == 0) { /* FLOAT * VEC */
|
||||
return vector_mul_float(vec2, scalar);
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Element-wise multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Multiplication in-place (element-wise or scalar): `object *= object`. */
|
||||
static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
float scalar;
|
||||
|
||||
if (VectorObject_Check(v1)) {
|
||||
vec1 = (VectorObject *)v1;
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (VectorObject_Check(v2)) {
|
||||
vec2 = (VectorObject *)v2;
|
||||
if (BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Intentionally don't support (Quaternion, Matrix) here, uses reverse order instead. */
|
||||
|
||||
if (vec1 && vec2) {
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector multiplication: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Element-wise product in-place. */
|
||||
mul_vn_vn(vec1->vec, vec2->vec, vec1->vec_num);
|
||||
}
|
||||
else if (vec1 && (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) ==
|
||||
0)) { /* VEC *= FLOAT */
|
||||
mul_vn_fl(vec1->vec, vec1->vec_num, scalar);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"In place element-wise multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/** Multiplication (matrix multiply): `object @ object`. */
|
||||
static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
VectorObject *vec1 = NULL, *vec2 = NULL;
|
||||
int vec_num;
|
||||
|
||||
if (VectorObject_Check(v1)) {
|
||||
vec1 = (VectorObject *)v1;
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (VectorObject_Check(v2)) {
|
||||
vec2 = (VectorObject *)v2;
|
||||
if (BaseMath_ReadCallback(vec2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Intentionally don't support (Quaternion) here, uses reverse order instead. */
|
||||
|
||||
/* make sure v1 is always the vector */
|
||||
if (vec1 && vec2) {
|
||||
if (vec1->vec_num != vec2->vec_num) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Vector multiplication: "
|
||||
"vectors must have the same dimensions for this operation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Dot product. */
|
||||
return PyFloat_FromDouble(dot_vn_vn(vec1->vec, vec2->vec, vec1->vec_num));
|
||||
}
|
||||
if (vec1) {
|
||||
if (MatrixObject_Check(v2)) {
|
||||
/* VEC @ MATRIX */
|
||||
float tvec[MAX_DIMENSIONS];
|
||||
|
||||
if (BaseMath_ReadCallback((MatrixObject *)v2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
if (row_vector_multiplication(tvec, vec1, (MatrixObject *)v2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (((MatrixObject *)v2)->row_num == 4 && vec1->vec_num == 3) {
|
||||
vec_num = 3;
|
||||
}
|
||||
else {
|
||||
vec_num = ((MatrixObject *)v2)->col_num;
|
||||
}
|
||||
|
||||
return Vector_CreatePyObject(tvec, vec_num, Py_TYPE(vec1));
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Vector multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Multiplication in-place (matrix multiply): `object @= object`. */
|
||||
static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"In place vector multiplication: "
|
||||
"not supported between '%.200s' and '%.200s' types",
|
||||
Py_TYPE(v1)->tp_name,
|
||||
Py_TYPE(v2)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Division: `object / object`. */
|
||||
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
float *vec = NULL, scalar;
|
||||
VectorObject *vec1 = NULL;
|
||||
|
||||
if (!VectorObject_Check(v1)) { /* not a vector */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector division: "
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
vec1 = (VectorObject *)v1; /* vector */
|
||||
|
||||
if (BaseMath_ReadCallback(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) {
|
||||
/* parsed item not a number */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector division: "
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (scalar == 0.0f) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError,
|
||||
"Vector division: "
|
||||
"divide by zero error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = PyMem_Malloc(vec1->vec_num * sizeof(float));
|
||||
|
||||
if (vec == NULL) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"vec / value: "
|
||||
"problem allocating pointer space");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_vn_fl(vec, vec1->vec, vec1->vec_num, 1.0f / scalar);
|
||||
|
||||
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
|
||||
}
|
||||
|
||||
/** Division in-place: `object /= object`. */
|
||||
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
|
||||
{
|
||||
float scalar;
|
||||
VectorObject *vec1 = (VectorObject *)v1;
|
||||
|
||||
if (BaseMath_ReadCallback_ForWrite(vec1) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) {
|
||||
/* parsed item not a number */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Vector division: "
|
||||
"Vector must be divided by a float");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (scalar == 0.0f) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError,
|
||||
"Vector division: "
|
||||
"divide by zero error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mul_vn_fl(vec1->vec, vec1->vec_num, 1.0f / scalar);
|
||||
|
||||
(void)BaseMath_WriteCallback(vec1);
|
||||
|
||||
Py_INCREF(v1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
/** Negative (returns the negative of this object): `-object`. */
|
||||
static PyObject *Vector_neg(VectorObject *self)
|
||||
{
|
||||
float *tvec;
|
||||
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tvec = PyMem_Malloc(self->vec_num * sizeof(float));
|
||||
negate_vn_vn(tvec, self->vec, self->vec_num);
|
||||
return Vector_CreatePyObject_alloc(tvec, self->vec_num, Py_TYPE(self));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Protocol Declarations
|
||||
* \{ */
|
||||
|
||||
static PySequenceMethods Vector_SeqMethods = {
|
||||
(lenfunc)Vector_len, /*sq_length*/
|
||||
(binaryfunc)NULL, /*sq_concat*/
|
||||
(ssizeargfunc)NULL, /*sq_repeat*/
|
||||
(ssizeargfunc)Vector_item, /*sq_item*/
|
||||
NULL, /*sq_slice(DEPRECATED)*/
|
||||
(ssizeobjargproc)Vector_ass_item, /*sq_ass_item*/
|
||||
NULL, /*sq_ass_slice(DEPRECATED)*/
|
||||
(objobjproc)NULL, /*sq_contains*/
|
||||
(binaryfunc)NULL, /*sq_inplace_concat */
|
||||
(ssizeargfunc)NULL, /*sq_inplace_repeat */
|
||||
};
|
||||
|
||||
static PyMappingMethods Vector_AsMapping = {
|
||||
(lenfunc)Vector_len,
|
||||
(binaryfunc)Vector_subscript,
|
||||
@@ -2202,28 +2425,32 @@ static PyNumberMethods Vector_NumMethods = {
|
||||
NULL, /*nb_int*/
|
||||
NULL, /*nb_reserved*/
|
||||
NULL, /*nb_float*/
|
||||
Vector_iadd, /* nb_inplace_add */
|
||||
Vector_isub, /* nb_inplace_subtract */
|
||||
Vector_imul, /* nb_inplace_multiply */
|
||||
NULL, /* nb_inplace_remainder */
|
||||
NULL, /* nb_inplace_power */
|
||||
NULL, /* nb_inplace_lshift */
|
||||
NULL, /* nb_inplace_rshift */
|
||||
NULL, /* nb_inplace_and */
|
||||
NULL, /* nb_inplace_xor */
|
||||
NULL, /* nb_inplace_or */
|
||||
NULL, /* nb_floor_divide */
|
||||
Vector_div, /* nb_true_divide */
|
||||
NULL, /* nb_inplace_floor_divide */
|
||||
Vector_idiv, /* nb_inplace_true_divide */
|
||||
NULL, /* nb_index */
|
||||
(binaryfunc)Vector_matmul, /* nb_matrix_multiply */
|
||||
(binaryfunc)Vector_imatmul, /* nb_inplace_matrix_multiply */
|
||||
Vector_iadd, /*nb_inplace_add*/
|
||||
Vector_isub, /*nb_inplace_subtract*/
|
||||
Vector_imul, /*nb_inplace_multiply*/
|
||||
NULL, /*nb_inplace_remainder*/
|
||||
NULL, /*nb_inplace_power*/
|
||||
NULL, /*nb_inplace_lshift*/
|
||||
NULL, /*nb_inplace_rshift*/
|
||||
NULL, /*nb_inplace_and*/
|
||||
NULL, /*nb_inplace_xor*/
|
||||
NULL, /*nb_inplace_or*/
|
||||
NULL, /*nb_floor_divide*/
|
||||
Vector_div, /*nb_true_divide*/
|
||||
NULL, /*nb_inplace_floor_divide*/
|
||||
Vector_idiv, /*nb_inplace_true_divide*/
|
||||
NULL, /*nb_index*/
|
||||
(binaryfunc)Vector_matmul, /*nb_matrix_multiply*/
|
||||
(binaryfunc)Vector_imatmul, /*nb_inplace_matrix_multiply*/
|
||||
};
|
||||
|
||||
/*------------------PY_OBECT DEFINITION--------------------------*/
|
||||
/** \} */
|
||||
|
||||
/* vector axis, vector.x/y/z/w */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Get/Set Item Implementation
|
||||
* \{ */
|
||||
|
||||
/* Vector axis: `vector.x/y/z/w`. */
|
||||
|
||||
PyDoc_STRVAR(Vector_axis_x_doc, "Vector X axis.\n\n:type: float");
|
||||
PyDoc_STRVAR(Vector_axis_y_doc, "Vector Y axis.\n\n:type: float");
|
||||
@@ -2240,7 +2467,7 @@ static int Vector_axis_set(VectorObject *self, PyObject *value, void *type)
|
||||
return vector_ass_item_internal(self, POINTER_AS_INT(type), value, true);
|
||||
}
|
||||
|
||||
/* vector.length */
|
||||
/* `Vector.length`. */
|
||||
|
||||
PyDoc_STRVAR(Vector_length_doc, "Vector Length.\n\n:type: float");
|
||||
static PyObject *Vector_length_get(VectorObject *self, void *UNUSED(closure))
|
||||
@@ -2296,7 +2523,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vector.length_squared */
|
||||
/* `Vector.length_squared`. */
|
||||
PyDoc_STRVAR(Vector_length_squared_doc, "Vector length squared (v.dot(v)).\n\n:type: float");
|
||||
static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(closure))
|
||||
{
|
||||
@@ -2503,9 +2730,12 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
|
||||
#define SWIZZLE3(a, b, c) POINTER_FROM_INT(_SWIZZLE3(a, b, c))
|
||||
#define SWIZZLE4(a, b, c, d) POINTER_FROM_INT(_SWIZZLE4(a, b, c, d))
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python attributes get/set structure: */
|
||||
/*****************************************************************************/
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Get/Set Item Definitions
|
||||
* \{ */
|
||||
|
||||
static PyGetSetDef Vector_getseters[] = {
|
||||
{"x", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_x_doc, (void *)0},
|
||||
{"y", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_y_doc, (void *)1},
|
||||
@@ -2886,68 +3116,11 @@ static PyGetSetDef Vector_getseters[] = {
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/**
|
||||
* Row vector multiplication - (Vector * Matrix)
|
||||
* <pre>
|
||||
* [x][y][z] * [1][4][7]
|
||||
* [2][5][8]
|
||||
* [3][6][9]
|
||||
* </pre>
|
||||
* \note vector/matrix multiplication is not commutative.
|
||||
*/
|
||||
static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS],
|
||||
VectorObject *vec,
|
||||
MatrixObject *mat)
|
||||
{
|
||||
float vec_cpy[MAX_DIMENSIONS];
|
||||
int row, col, z = 0, vec_num = vec->vec_num;
|
||||
/** \} */
|
||||
|
||||
if (mat->row_num != vec_num) {
|
||||
if (mat->row_num == 4 && vec_num == 3) {
|
||||
vec_cpy[3] = 1.0f;
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"vector * matrix: matrix column size "
|
||||
"and the vector size must be the same");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(vec_cpy, vec->vec, vec_num * sizeof(float));
|
||||
|
||||
r_vec[3] = 1.0f;
|
||||
/* Multiplication. */
|
||||
for (col = 0; col < mat->col_num; col++) {
|
||||
double dot = 0.0;
|
||||
for (row = 0; row < mat->row_num; row++) {
|
||||
dot += (double)(MATRIX_ITEM(mat, row, col) * vec_cpy[row]);
|
||||
}
|
||||
r_vec[z++] = (float)dot;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------Vector.negate() -------------------- */
|
||||
PyDoc_STRVAR(Vector_negate_doc,
|
||||
".. method:: negate()\n"
|
||||
"\n"
|
||||
" Set all values to their negative.\n");
|
||||
static PyObject *Vector_negate(VectorObject *self)
|
||||
{
|
||||
if (BaseMath_ReadCallback(self) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
negate_vn(self->vec, self->vec_num);
|
||||
|
||||
(void)BaseMath_WriteCallback(self); /* already checked for error */
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Method Definitions
|
||||
* \{ */
|
||||
|
||||
static struct PyMethodDef Vector_methods[] = {
|
||||
/* Class Methods */
|
||||
@@ -3000,11 +3173,15 @@ static struct PyMethodDef Vector_methods[] = {
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
/**
|
||||
* NOTE: #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: Python Object Definition
|
||||
*
|
||||
* \note #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
|
||||
* but this means for eg that (vec * mat) and (mat * vec)
|
||||
* both get sent to Vector_mul and it needs to sort out the order
|
||||
*/
|
||||
* \{ */
|
||||
|
||||
PyDoc_STRVAR(vector_doc,
|
||||
".. class:: Vector(seq)\n"
|
||||
@@ -3098,6 +3275,12 @@ PyTypeObject vector_Type = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Vector Type: C/API Constructors
|
||||
* \{ */
|
||||
|
||||
PyObject *Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
|
||||
{
|
||||
VectorObject *self;
|
||||
@@ -3190,3 +3373,5 @@ PyObject *Vector_CreatePyObject_alloc(float *vec, const int vec_num, PyTypeObjec
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -18,7 +18,8 @@ typedef struct {
|
||||
int vec_num;
|
||||
} VectorObject;
|
||||
|
||||
/*prototypes*/
|
||||
/* Prototypes. */
|
||||
|
||||
PyObject *Vector_CreatePyObject(const float *vec,
|
||||
int vec_num,
|
||||
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
Reference in New Issue
Block a user