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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/python/mathutils/mathutils_Vector.c')
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c835
1 files changed, 510 insertions, 325 deletions
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index ffeb121b3d1..0c9cbd6ccfa 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -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,13 +1554,124 @@ static PyObject *Vector_str(VectorObject *self)
}
#endif
-/* Sequence Protocol */
-/* sequence length len(vector) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Rich Compare
+ * \{ */
+
+static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ VectorObject *vecA = NULL, *vecB = NULL;
+ int result = 0;
+ const double epsilon = 0.000001f;
+ double lenA, lenB;
+
+ if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+ }
+ vecA = (VectorObject *)objectA;
+ vecB = (VectorObject *)objectB;
+
+ if (BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) {
+ return NULL;
+ }
+
+ if (vecA->vec_num != vecB->vec_num) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+ }
+
+ switch (comparison_type) {
+ case Py_LT:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA < lenB) {
+ result = 1;
+ }
+ break;
+ case Py_LE:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA < lenB) {
+ result = 1;
+ }
+ else {
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ case Py_EQ:
+ result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
+ break;
+ case Py_NE:
+ result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
+ break;
+ case Py_GT:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA > lenB) {
+ result = 1;
+ }
+ break;
+ case Py_GE:
+ lenA = len_squared_vn(vecA->vec, vecA->vec_num);
+ lenB = len_squared_vn(vecB->vec, vecB->vec_num);
+ if (lenA > lenB) {
+ result = 1;
+ }
+ else {
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1) {
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Hash (`__hash__`)
+ * \{ */
+
+static Py_hash_t Vector_hash(VectorObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1) {
+ return -1;
+ }
+
+ if (BaseMathObject_Prepare_ForHash(self) == -1) {
+ return -1;
+ }
+
+ return mathutils_array_hash(self->vec, self->vec_num);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Sequence & Mapping Protocols Implementation
+ * \{ */
+
+/** Sequence length: `len(object)`. */
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) {
@@ -1395,11 +1698,12 @@ static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_a
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);
}
-/* sequence accessor (set): vector[index] = value */
+
static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const bool is_attr)
{
float scalar;
@@ -1442,12 +1746,13 @@ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value,
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 (get): vector[a:b] */
+/** Sequence slice accessor (get): `x = object[i:j]`. */
static PyObject *Vector_slice(VectorObject *self, int begin, int end)
{
PyObject *tuple;
@@ -1471,7 +1776,8 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
return tuple;
}
-/* sequence slice (set): vector[a:b] = value */
+
+/** 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;
@@ -1509,8 +1815,83 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
return 0;
}
-/* Numeric Protocols */
-/* addition: obj + obj */
+/** Sequence generic subscript (get): `x = object[...]`. */
+static PyObject *Vector_subscript(VectorObject *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->vec_num;
+ }
+ return Vector_item(self, i);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
+ return NULL;
+ }
+
+ if (slicelength <= 0) {
+ return PyTuple_New(0);
+ }
+ if (step == 1) {
+ return Vector_slice(self, start, stop);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
+ return NULL;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return NULL;
+}
+
+/** Sequence generic subscript (set): `object[...] = x`. */
+static int Vector_ass_subscript(VectorObject *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->vec_num;
+ }
+ return Vector_ass_item(self, i, value);
+ }
+ if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
+ return -1;
+ }
+
+ if (step == 1) {
+ return Vector_ass_slice(self, start, stop, value);
+ }
+
+ PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
+ return -1;
+ }
+
+ PyErr_Format(
+ PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+ return -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Numeric Protocol Implementation
+ * \{ */
+
+/** Addition: `object + object`. */
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1552,7 +1933,7 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* addition in-place: obj += obj */
+/** Addition in-place: `object += object`. */
static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1586,7 +1967,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
return v1;
}
-/* subtraction: obj - obj */
+/** Subtraction: `object - object`. */
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1627,7 +2008,7 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* subtraction in-place: obj -= obj */
+/** Subtraction in-place: `object -= object`. */
static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1661,8 +2042,7 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
return v1;
}
-/*------------------------obj * obj------------------------------
- * multiplication */
+/* Multiply internal implementation `object * object`, `object *= object`. */
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
@@ -1725,6 +2105,7 @@ static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
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;
@@ -1776,7 +2157,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
return NULL;
}
-/* multiplication in-place: obj *= obj */
+/** Multiplication in-place (element-wise or scalar): `object *= object`. */
static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1830,6 +2211,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
return v1;
}
+/** Multiplication (matrix multiply): `object @ object`. */
static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1893,6 +2275,7 @@ static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
return NULL;
}
+/** Multiplication in-place (matrix multiply): `object @= object`. */
static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
{
PyErr_Format(PyExc_TypeError,
@@ -1903,7 +2286,7 @@ static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
return NULL;
}
-/* divide: obj / obj */
+/** Division: `object / object`. */
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
{
float *vec = NULL, scalar;
@@ -1950,7 +2333,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject_alloc(vec, vec1->vec_num, Py_TYPE(v1));
}
-/* divide in-place: obj /= obj */
+/** Division in-place: `object /= object`. */
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
{
float scalar;
@@ -1983,8 +2366,7 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
return v1;
}
-/* -obj
- * Returns the negative of this object. */
+/** Negative (returns the negative of this object): `-object`. */
static PyObject *Vector_neg(VectorObject *self)
{
float *tvec;
@@ -1998,184 +2380,25 @@ static PyObject *Vector_neg(VectorObject *self)
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;
- int result = 0;
- const double epsilon = 0.000001f;
- double lenA, lenB;
-
- if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) {
- if (comparison_type == Py_NE) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
- }
- vecA = (VectorObject *)objectA;
- vecB = (VectorObject *)objectB;
-
- if (BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) {
- return NULL;
- }
+/** \} */
- if (vecA->vec_num != vecB->vec_num) {
- if (comparison_type == Py_NE) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
- }
-
- switch (comparison_type) {
- case Py_LT:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA < lenB) {
- result = 1;
- }
- break;
- case Py_LE:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA < lenB) {
- result = 1;
- }
- else {
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- case Py_EQ:
- result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
- break;
- case Py_NE:
- result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->vec_num, 1);
- break;
- case Py_GT:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA > lenB) {
- result = 1;
- }
- break;
- case Py_GE:
- lenA = len_squared_vn(vecA->vec, vecA->vec_num);
- lenB = len_squared_vn(vecB->vec, vecB->vec_num);
- if (lenA > lenB) {
- result = 1;
- }
- else {
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1) {
- Py_RETURN_TRUE;
- }
-
- Py_RETURN_FALSE;
-}
-
-static Py_hash_t Vector_hash(VectorObject *self)
-{
- if (BaseMath_ReadCallback(self) == -1) {
- return -1;
- }
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Protocol Declarations
+ * \{ */
- if (BaseMathObject_Prepare_ForHash(self) == -1) {
- return -1;
- }
-
- 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 */
+ (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 PyObject *Vector_subscript(VectorObject *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->vec_num;
- }
- return Vector_item(self, i);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
- return NULL;
- }
-
- if (slicelength <= 0) {
- return PyTuple_New(0);
- }
- if (step == 1) {
- return Vector_slice(self, start, stop);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
- return NULL;
- }
-
- PyErr_Format(
- PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return NULL;
-}
-
-static int Vector_ass_subscript(VectorObject *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->vec_num;
- }
- return Vector_ass_item(self, i, value);
- }
- if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx(item, self->vec_num, &start, &stop, &step, &slicelength) < 0) {
- return -1;
- }
-
- if (step == 1) {
- return Vector_ass_slice(self, start, stop, value);
- }
-
- PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors");
- return -1;
- }
-
- PyErr_Format(
- PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
- return -1;
-}
-
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--------------------------*/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Type: Get/Set Item Implementation
+ * \{ */
-/* vector axis, vector.x/y/z/w */
+/* 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;
}
+
+/** \} */