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
path: root/source
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2011-12-18 11:27:11 +0400
committerCampbell Barton <ideasman42@gmail.com>2011-12-18 11:27:11 +0400
commit414370b8d42324878485e569fc332b814131887f (patch)
tree84b9b3077cccc3a5237bb8c033b6b39859cf9538 /source
parentbfdaa3b187b947a0efcf3a02cb70bbe8aff5e301 (diff)
Support for arbitrary sized vectors - (was limited by 2-4 previously)
patch http://codereview.appspot.com/5482043 from Andrew Hale * Text from the submission * This patch adds the ability to use arbitrary sized vectors from mathutils. Currently vectors are only of size 2, 3 or 4 since they are generally restricted to geometric applications. However, we can use arbitrary sized vectors for efficient calculations and data manipulation.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenlib/BLI_math_vector.h1
-rw-r--r--source/blender/blenlib/intern/math_vector.c9
-rw-r--r--source/blender/python/mathutils/mathutils.c114
-rw-r--r--source/blender/python/mathutils/mathutils.h1
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c516
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h3
6 files changed, 563 insertions, 81 deletions
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index d8e880a9dec..e9e44ed7b2c 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -198,6 +198,7 @@ double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int s
float normalize_vn_vn(float *array_tar, const float *array_src, const int size);
float normalize_vn(float *array_tar, const int size);
void range_vn_i(int *array_tar, const int size, const int start);
+void range_vn_fl(float *array_tar, const int size, const float start, const float step);
void negate_vn(float *array_tar, const int size);
void negate_vn_vn(float *array_tar, const float *array_src, const int size);
void mul_vn_fl(float *array_tar, const int size, const float f);
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index a9ea90ef555..590a48e8085 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -416,6 +416,15 @@ void range_vn_i(int *array_tar, const int size, const int start)
while(i--) { *(array_pt--) = j--; }
}
+void range_vn_fl(float *array_tar, const int size, const float start, const float step)
+{
+ float *array_pt= array_tar + (size-1);
+ int i= size;
+ while(i--) {
+ *(array_pt--) = start + step * (float)(i);
+ }
+}
+
void negate_vn(float *array_tar, const int size)
{
float *array_pt= array_tar + (size-1);
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 121c5e26e73..6a7f54d6f81 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -40,36 +40,13 @@ PyDoc_STRVAR(M_Mathutils_doc,
"This module provides access to matrices, eulers, quaternions and vectors."
);
static int mathutils_array_parse_fast(float *array,
- int array_min, int array_max,
- PyObject *value, const char *error_prefix)
+ int size,
+ PyObject *value_fast,
+ const char *error_prefix)
{
- PyObject *value_fast= NULL;
PyObject *item;
- int i, size;
-
- /* non list/tuple cases */
- if (!(value_fast=PySequence_Fast(value, error_prefix))) {
- /* PySequence_Fast sets the error */
- return -1;
- }
-
- size= PySequence_Fast_GET_SIZE(value_fast);
-
- if (size > array_max || size < array_min) {
- if (array_max == array_min) {
- PyErr_Format(PyExc_ValueError,
- "%.200s: sequence size is %d, expected %d",
- error_prefix, size, array_max);
- }
- else {
- PyErr_Format(PyExc_ValueError,
- "%.200s: sequence size is %d, expected [%d - %d]",
- error_prefix, size, array_min, array_max);
- }
- Py_DECREF(value_fast);
- return -1;
- }
+ int i;
i= size;
do {
@@ -93,9 +70,10 @@ static int mathutils_array_parse_fast(float *array,
/* helper functionm returns length of the 'value', -1 on error */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
-#if 1 /* approx 6x speedup for mathutils types */
int size;
+#if 1 /* approx 6x speedup for mathutils types */
+
if ( (size= VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
(size= EulerObject_Check(value) ? 3 : 0) ||
(size= QuaternionObject_Check(value) ? 4 : 0) ||
@@ -125,7 +103,85 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
else
#endif
{
- return mathutils_array_parse_fast(array, array_min, array_max, value, error_prefix);
+ PyObject *value_fast= NULL;
+
+ /* non list/tuple cases */
+ if (!(value_fast=PySequence_Fast(value, error_prefix))) {
+ /* PySequence_Fast sets the error */
+ return -1;
+ }
+
+ size= PySequence_Fast_GET_SIZE(value_fast);
+
+ if (size > array_max || size < array_min) {
+ if (array_max == array_min) {
+ PyErr_Format(PyExc_ValueError,
+ "%.200s: sequence size is %d, expected %d",
+ error_prefix, size, array_max);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "%.200s: sequence size is %d, expected [%d - %d]",
+ error_prefix, size, array_min, array_max);
+ }
+ Py_DECREF(value_fast);
+ return -1;
+ }
+
+ return mathutils_array_parse_fast(array, size, value_fast, error_prefix);
+ }
+}
+
+int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix)
+{
+ int size;
+
+#if 1 /* approx 6x speedup for mathutils types */
+
+ if ( (size= VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) ||
+ (size= EulerObject_Check(value) ? 3 : 0) ||
+ (size= QuaternionObject_Check(value) ? 4 : 0) ||
+ (size= ColorObject_Check(value) ? 3 : 0))
+ {
+ if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
+ return -1;
+ }
+
+ if (size < array_min) {
+ PyErr_Format(PyExc_ValueError,
+ "%.200s: sequence size is %d, expected > %d",
+ error_prefix, size, array_min);
+ return -1;
+ }
+
+ *array= PyMem_Malloc(size * sizeof(float));
+ memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
+ return size;
+ }
+ else
+#endif
+ {
+ PyObject *value_fast= NULL;
+ //*array= NULL;
+
+ /* non list/tuple cases */
+ if (!(value_fast=PySequence_Fast(value, error_prefix))) {
+ /* PySequence_Fast sets the error */
+ return -1;
+ }
+
+ size= PySequence_Fast_GET_SIZE(value_fast);
+
+ if (size < array_min) {
+ PyErr_Format(PyExc_ValueError,
+ "%.200s: sequence size is %d, expected > %d",
+ error_prefix, size, array_min);
+ return -1;
+ }
+
+ *array= PyMem_Malloc(size * sizeof(float));
+
+ return mathutils_array_parse_fast(*array, size, value_fast, error_prefix);
}
}
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index a8170b8145c..cd3548b9b82 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -115,6 +115,7 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
/* utility func */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
+int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
int column_vector_multiplication(float rvec[4], VectorObject *vec, MatrixObject *mat);
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 9d1a22adb12..a812311dad4 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -54,15 +54,29 @@ static int row_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject *v
*/
static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *UNUSED(kwds))
{
- float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+ float *vec= NULL;
int size= 3; /* default to a 3D vector */
switch(PyTuple_GET_SIZE(args)) {
case 0:
+ vec= PyMem_Malloc(size * sizeof(float));
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ fill_vn_fl(vec, size, 0.0f);
break;
case 1:
- if ((size=mathutils_array_parse(vec, 2, 4, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1)
+ if ((size=mathutils_array_parse_alloc(&vec, 2, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1) {
+ if (vec) {
+ PyMem_Free(vec);
+ }
return NULL;
+ }
break;
default:
PyErr_SetString(PyExc_TypeError,
@@ -87,6 +101,215 @@ static PyObject *vec__apply_to_copy(PyNoArgsFunction vec_func, VectorObject *sel
}
}
+/*-----------------------CLASS-METHODS----------------------------*/
+PyDoc_STRVAR(C_Vector_Fill_doc,
+".. classmethod:: Fill(size, fill=0.0)\n"
+"\n"
+" Create a vector of length size with all values set to fill.\n"
+"\n"
+" :arg size: The length of the vector to be created.\n"
+" :type size: int\n"
+" :arg fill: The value used to fill the vector.\n"
+" :type fill: float\n"
+);
+static PyObject *C_Vector_Fill(PyObject *cls, PyObject *args)
+{
+ float *vec;
+ int size;
+ float fill= 0.0f;
+
+ if (!PyArg_ParseTuple(args, "i|f:Vector.Fill", &size, &fill)) {
+ return NULL;
+ }
+
+ if (size < 2) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Vector(): invalid size");
+ return NULL;
+ }
+
+ vec= PyMem_Malloc(size * sizeof(float));
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.Fill(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ fill_vn_fl(vec, size, fill);
+
+ return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
+}
+
+PyDoc_STRVAR(C_Vector_Range_doc,
+".. classmethod:: Range(start=0, stop, step=1)\n"
+"\n"
+" Create a filled with a range of values.\n"
+"\n"
+" :arg start: The start of the range used to fill the vector.\n"
+" :type start: int\n"
+" :arg stop: The end of the range used to fill the vector.\n"
+" :type stop: int\n"
+" :arg step: The step between successive values in the vector.\n"
+" :type step: int\n"
+);
+static PyObject *C_Vector_Range(PyObject *cls, PyObject *args)
+{
+ float *vec;
+ int stop, size;
+ int start= 0;
+ int step= 1;
+
+ if (!PyArg_ParseTuple(args, "i|ii:Vector.Range", &start, &stop, &step)) {
+ return NULL;
+ }
+
+ switch(PyTuple_GET_SIZE(args)){
+ case 1:
+ size = start;
+ start= 0;
+ break;
+ case 2:
+ if (start >= stop) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Start value is larger"
+ "than the stop value");
+ return NULL;
+ }
+
+ size= stop - start;
+ break;
+ default:
+ if (start >= stop) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Start value is larger"
+ "than the stop value");
+ return NULL;
+ }
+ size= (stop - start)/step;
+ if (size%step)
+ size++;
+ break;
+ }
+
+ vec= PyMem_Malloc(size * sizeof(float));
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.Range(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ range_vn_fl(vec, size, (float)start, (float)step);
+
+ return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
+}
+
+PyDoc_STRVAR(C_Vector_Linspace_doc,
+".. classmethod:: Linspace(start, stop, size)\n"
+"\n"
+" Create a vector of the specified size which is filled with linearly spaced values between start and stop values.\n"
+"\n"
+" :arg start: The start of the range used to fill the vector.\n"
+" :type start: int\n"
+" :arg stop: The end of the range used to fill the vector.\n"
+" :type stop: int\n"
+" :arg size: The size of the vector to be created.\n"
+" :type size: int\n"
+);
+static PyObject *C_Vector_Linspace(PyObject *cls, PyObject *args)
+{
+ float *vec;
+ int size;
+ float start, end, step;
+
+ if (!PyArg_ParseTuple(args, "ffi:Vector.Linspace", &start, &end, &size)) {
+ return NULL;
+ }
+
+ if (size < 2) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Vector.Linspace(): invalid size");
+ return NULL;
+ }
+
+ step= (end - start)/(float)(size-1);
+
+ vec= PyMem_Malloc(size * sizeof(float));
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.Linspace(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ range_vn_fl(vec, size, start, step);
+
+ return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
+}
+
+PyDoc_STRVAR(C_Vector_Repeat_doc,
+".. classmethod:: Repeat(vector, size)\n"
+"\n"
+" Create a vector by repeating the values in vector until the required size is reached.\n"
+"\n"
+" :arg tuple: The vector to draw values from.\n"
+" :type tuple: :class:`mathutils.Vector`\n"
+" :arg size: The size of the vector to be created.\n"
+" :type size: int\n"
+);
+static PyObject *C_Vector_Repeat(PyObject *cls, PyObject *args)
+{
+ float *vec;
+ float *iter_vec= NULL;
+ int i, size, value_size;
+ PyObject *value;
+
+ if (!PyArg_ParseTuple(args, "Oi:Vector.Repeat", &value, &size)) {
+ return NULL;
+ }
+
+ if (size < 2) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Vector.Repeat(): invalid size");
+ return NULL;
+ }
+
+ if ((value_size=mathutils_array_parse_alloc(&iter_vec, 2, value, "Vector.Repeat(vector, size), invalid 'vector' arg")) == -1) {
+ PyMem_Free(iter_vec);
+ return NULL;
+ }
+
+ if (iter_vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.Repeat(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ vec= PyMem_Malloc(size * sizeof(float));
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.Repeat(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ i= 0;
+ while (i < size) {
+ vec[i]= iter_vec[i % value_size];
+ i++;
+ }
+
+ PyMem_Free(iter_vec);
+
+ return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
+}
+
/*-----------------------------METHODS---------------------------- */
PyDoc_STRVAR(Vector_zero_doc,
".. method:: zero()\n"
@@ -137,6 +360,101 @@ static PyObject *Vector_normalized(VectorObject *self)
return vec__apply_to_copy((PyNoArgsFunction)Vector_normalize, self);
}
+PyDoc_STRVAR(Vector_resize_doc,
+".. method:: resize(size=3)\n"
+"\n"
+" Resize the vector to have size number of elements.\n"
+"\n"
+" :return: an instance of itself\n"
+" :rtype: :class:`Vector`\n"
+);
+static PyObject *Vector_resize(VectorObject *self, PyObject *value)
+{
+ int size;
+
+ if (self->wrapped==Py_WRAP) {
+ PyErr_SetString(PyExc_TypeError,
+ "Vector.resize(): "
+ "cannot resize wrapped data - only python vectors");
+ return NULL;
+ }
+ if (self->cb_user) {
+ PyErr_SetString(PyExc_TypeError,
+ "Vector.resize(): "
+ "cannot resize a vector that has an owner");
+ return NULL;
+ }
+
+ if ((size = PyLong_AsLong(value)) == -1) {
+ PyErr_SetString(PyExc_TypeError,
+ "Vector.resize(size): "
+ "expected size argument to be an integer");
+ return NULL;
+ }
+
+ if (size < 2) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Vector.resize(): invalid size");
+ return NULL;
+ }
+
+ self->vec = PyMem_Realloc(self->vec, (size * sizeof(float)));
+ if (self->vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.resize(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ /* If the vector has increased in length, set all new elements to 0.0f */
+ if (size > self->size) {
+ fill_vn_fl(self->vec + self->size, size - self->size, 0.0f);
+ }
+
+ self->size = size;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Vector_resized_doc,
+".. method:: resized(size=3)\n"
+"\n"
+" Return a resized copy of the vector with size number of elements.\n"
+"\n"
+" :return: a new vector\n"
+" :rtype: :class:`Vector`\n"
+);
+static PyObject *Vector_resized(VectorObject *self, PyObject *value)
+{
+ int size;
+ float *vec;
+
+ /*if (!PyArg_ParseTuple(args, "i:resize", &size))
+ return NULL;*/
+ if ((size = PyLong_AsLong(value)) == -1){
+ return NULL;
+ }
+
+ if (size < 2) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Vector.resized(): invalid size");
+ return NULL;
+ }
+
+ vec= PyMem_Malloc(size * sizeof(float));
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.resized(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
+ fill_vn_fl(vec, size, 0.0f);
+ memcpy(vec, self->vec, self->size * sizeof(float));
+
+ return Vector_CreatePyObject_alloc(vec, size, NULL);
+}
+
PyDoc_STRVAR(Vector_resize_2d_doc,
".. method:: resize_2d()\n"
"\n"
@@ -505,6 +823,12 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
if ((value_size= mathutils_array_parse(tvec, 2, 4, value, "Vector.reflect(other), invalid 'other' arg")) == -1)
return NULL;
+ if (self->size < 2 || self->size > 4) {
+ PyErr_SetString(PyExc_ValueError,
+ "Vector must be 2D, 3D or 4D");
+ return NULL;
+ }
+
mirror[0] = tvec[0];
mirror[1] = tvec[1];
if (value_size > 2) mirror[2] = tvec[2];
@@ -544,6 +868,12 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value)
if (mathutils_array_parse(tvec, self->size, self->size, value, "Vector.cross(other), invalid 'other' arg") == -1)
return NULL;
+ if (self->size != 3) {
+ PyErr_SetString(PyExc_ValueError,
+ "Vector must be 3D");
+ return NULL;
+ }
+
ret= (VectorObject *)Vector_CreatePyObject(NULL, 3, Py_NEW, Py_TYPE(self));
cross_v3_v3v3(ret->vec, self->vec, tvec);
return (PyObject *)ret;
@@ -561,15 +891,20 @@ PyDoc_STRVAR(Vector_dot_doc,
);
static PyObject *Vector_dot(VectorObject *self, PyObject *value)
{
- float tvec[MAX_DIMENSIONS];
+ float *tvec;
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- if (mathutils_array_parse(tvec, self->size, self->size, value, "Vector.dot(other), invalid 'other' arg") == -1)
- return NULL;
+ if (mathutils_array_parse_alloc(&tvec, self->size, value, "Vector.dot(other), invalid 'other' arg") == -1) {
+ goto cleanup;
+ }
return PyFloat_FromDouble(dot_vn_vn(self->vec, tvec, self->size));
+
+cleanup:
+ PyMem_Free(tvec);
+ return NULL;
}
PyDoc_STRVAR(Vector_angle_doc,
@@ -607,6 +942,12 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args)
if (mathutils_array_parse(tvec, self->size, self->size, value, "Vector.angle(other), invalid 'other' arg") == -1)
return NULL;
+ if (self->size > 4) {
+ PyErr_SetString(PyExc_ValueError,
+ "Vector must be 2D, 3D or 4D");
+ return NULL;
+ }
+
for (x = 0; x < size; x++) {
dot_self += (double)self->vec[x] * (double)self->vec[x];
dot_other += (double)tvec[x] * (double)tvec[x];
@@ -647,7 +988,7 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value)
{
float quat[4], vec_a[3], vec_b[3];
- if (self->size < 3) {
+ if (self->size < 3 || self->size > 4) {
PyErr_SetString(PyExc_ValueError,
"vec.difference(value): "
"expects both vectors to be size 3 or 4");
@@ -692,6 +1033,12 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value)
if (mathutils_array_parse(tvec, size, size, value, "Vector.project(other), invalid 'other' arg") == -1)
return NULL;
+ if (self->size > 4) {
+ PyErr_SetString(PyExc_ValueError,
+ "Vector must be 2D, 3D or 4D");
+ return NULL;
+ }
+
if (BaseMath_ReadCallback(self) == -1)
return NULL;
@@ -725,24 +1072,41 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
const int size= self->size;
PyObject *value= NULL;
float fac, ifac;
- float tvec[MAX_DIMENSIONS], vec[MAX_DIMENSIONS];
+ float *tvec, *vec;
int x;
if (!PyArg_ParseTuple(args, "Of:lerp", &value, &fac))
return NULL;
- if (mathutils_array_parse(tvec, size, size, value, "Vector.lerp(other), invalid 'other' arg") == -1)
- return NULL;
+ if (mathutils_array_parse_alloc(&tvec, size, value, "Vector.lerp(other), invalid 'other' arg") == -1) {
+ goto cleanup;
+ }
- if (BaseMath_ReadCallback(self) == -1)
+ if (BaseMath_ReadCallback(self) == -1) {
+ goto cleanup;
+ }
+
+ vec= PyMem_Malloc(size * sizeof(float));
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector.lerp(): "
+ "problem allocating pointer space");
return NULL;
+ }
ifac= 1.0f - fac;
for (x = 0; x < size; x++) {
vec[x] = (ifac * self->vec[x]) + (fac * tvec[x]);
}
- return Vector_CreatePyObject(vec, size, Py_NEW, Py_TYPE(self));
+
+ PyMem_Free(tvec);
+
+ return Vector_CreatePyObject_alloc(vec, size, Py_TYPE(self));
+
+cleanup:
+ PyMem_Free(tvec);
+ return NULL;
}
PyDoc_STRVAR(Vector_rotate_doc,
@@ -763,7 +1127,7 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
if (mathutils_any_to_rotmat(other_rmat, value, "Vector.rotate(value)") == -1)
return NULL;
- if (self->size < 3) {
+ if (self->size < 3 || self->size > 4) {
PyErr_SetString(PyExc_ValueError,
"Vector must be 3D or 4D");
return NULL;
@@ -903,8 +1267,8 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
/* sequence slice (set): vector[a:b] = value */
static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq)
{
- int y, size = 0;
- float vec[MAX_DIMENSIONS];
+ int size = 0;
+ float *vec= NULL;
if (BaseMath_ReadCallback(self) == -1)
return -1;
@@ -914,18 +1278,30 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
begin = MIN2(begin, end);
size = (end - begin);
- if (mathutils_array_parse(vec, size, size, seq, "vector[begin:end] = [...]") == -1)
+ if (mathutils_array_parse_alloc(&vec, size, seq, "vector[begin:end] = [...]") == -1) {
+ goto cleanup;
+ }
+
+ if (vec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "vec[:] = seq: "
+ "problem allocating pointer space");
return -1;
+ }
/*parsed well - now set in vector*/
- for (y = 0; y < size; y++) {
- self->vec[begin + y] = vec[y];
- }
+ memcpy(self->vec + begin, vec, size * sizeof(float));
if (BaseMath_WriteCallback(self) == -1)
return -1;
+ PyMem_Free(vec);
+
return 0;
+
+cleanup:
+ PyMem_Free(vec);
+ return -1;
}
/* Numeric Protocols */
@@ -933,7 +1309,7 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se
static PyObject *Vector_add(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
- float vec[MAX_DIMENSIONS];
+ float *vec= NULL;
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
PyErr_Format(PyExc_AttributeError,
@@ -956,9 +1332,18 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2)
return NULL;
}
+ vec= PyMem_Malloc(vec1->size * sizeof(float));
+
+ if (vec == NULL) { /*allocation failure*/
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
add_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size);
- return Vector_CreatePyObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
+ return Vector_CreatePyObject_alloc(vec, vec1->size, Py_TYPE(v1));
}
/* addition in-place: obj += obj */
@@ -997,7 +1382,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2)
static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
- float vec[MAX_DIMENSIONS];
+ float *vec;
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
PyErr_Format(PyExc_AttributeError,
@@ -1019,9 +1404,18 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2)
return NULL;
}
+ vec= PyMem_Malloc(vec1->size * sizeof(float));
+
+ if (vec == NULL) { /*allocation failure*/
+ PyErr_SetString(PyExc_MemoryError,
+ "Vector(): "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
sub_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size);
- return Vector_CreatePyObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
+ return Vector_CreatePyObject_alloc(vec, vec1->size, Py_TYPE(v1));
}
/* subtraction in-place: obj -= obj */
@@ -1104,9 +1498,18 @@ int column_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject* vec,
static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
{
- float tvec[MAX_DIMENSIONS];
+ float *tvec= NULL;
+ tvec= PyMem_Malloc(vec->size * sizeof(float));
+
+ if (tvec == NULL) { /*allocation failure*/
+ PyErr_SetString(PyExc_MemoryError,
+ "vec * float: "
+ "problem allocating pointer space");
+ return NULL;
+ }
+
mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar);
- return Vector_CreatePyObject(tvec, vec->size, Py_NEW, Py_TYPE(vec));
+ return Vector_CreatePyObject_alloc(tvec, vec->size, Py_TYPE(vec));
}
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
@@ -1277,8 +1680,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
/* divid: obj / obj */
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
{
- int i;
- float vec[4], scalar;
+ float *vec= NULL, scalar;
VectorObject *vec1 = NULL;
if (!VectorObject_Check(v1)) { /* not a vector */
@@ -1287,7 +1689,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
"Vector must be divided by a float");
return NULL;
}
- vec1 = (VectorObject*)v1; /* vector */
+ vec1 = (VectorObject *)v1; /* vector */
if (BaseMath_ReadCallback(vec1) == -1)
return NULL;
@@ -1306,16 +1708,23 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2)
return NULL;
}
- for (i = 0; i < vec1->size; i++) {
- vec[i] = vec1->vec[i] / scalar;
+ vec= PyMem_Malloc(vec1->size * sizeof(float));
+
+ if (vec == NULL) { /*allocation failure*/
+ PyErr_SetString(PyExc_MemoryError,
+ "vec / value: "
+ "problem allocating pointer space");
+ return NULL;
}
- return Vector_CreatePyObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
+
+ mul_vn_vn_fl(vec, vec1->vec, vec1->size, 1.0f/scalar);
+
+ return Vector_CreatePyObject_alloc(vec, vec1->size, Py_TYPE(v1));
}
/* divide in-place: obj /= obj */
static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
{
- int i;
float scalar;
VectorObject *vec1 = (VectorObject*)v1;
@@ -1335,9 +1744,8 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
"divide by zero error");
return NULL;
}
- for (i = 0; i < vec1->size; i++) {
- vec1->vec[i] /= scalar;
- }
+
+ mul_vn_fl(vec1->vec, vec1->size, 1.0f/scalar);
(void)BaseMath_WriteCallback(vec1);
@@ -1349,29 +1757,24 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2)
returns the negative of this object*/
static PyObject *Vector_neg(VectorObject *self)
{
- float tvec[MAX_DIMENSIONS];
+ float *tvec;
if (BaseMath_ReadCallback(self) == -1)
return NULL;
+ tvec= PyMem_Malloc(self->size * sizeof(float));
negate_vn_vn(tvec, self->vec, self->size);
- return Vector_CreatePyObject(tvec, self->size, Py_NEW, Py_TYPE(self));
+ return Vector_CreatePyObject_alloc(tvec, self->size, Py_TYPE(self));
}
/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */
static double vec_magnitude_nosqrt(float *data, int size)
{
- double dot = 0.0f;
- int i;
-
- for (i=0; i<size; i++) {
- dot += (double)data[i];
- }
/*return (double)sqrt(dot);*/
/* warning, line above removed because we are not using the length,
rather the comparing the sizes and for this we do not need the sqrt
for the actual length, the dot must be sqrt'd */
- return dot;
+ return dot_vn_vn(data, data, size);
}
@@ -1606,16 +2009,10 @@ static int Vector_setAxis(VectorObject *self, PyObject *value, void *type)
/* vector.length */
static PyObject *Vector_getLength(VectorObject *self, void *UNUSED(closure))
{
- double dot = 0.0f;
- int i;
-
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- for (i = 0; i < self->size; i++) {
- dot += (double)(self->vec[i] * self->vec[i]);
- }
- return PyFloat_FromDouble(sqrt(dot));
+ return PyFloat_FromDouble(sqrt(dot_vn_vn(self->vec, self->vec, self->size)));
}
static int Vector_setLength(VectorObject *self, PyObject *value)
@@ -2242,6 +2639,12 @@ static PyObject *Vector_negate(VectorObject *self)
}
static struct PyMethodDef Vector_methods[] = {
+ /* Class Methods */
+ {"Fill", (PyCFunction) C_Vector_Fill, METH_VARARGS | METH_CLASS, C_Vector_Fill_doc},
+ {"Range", (PyCFunction) C_Vector_Range, METH_VARARGS | METH_CLASS, C_Vector_Range_doc},
+ {"Linspace", (PyCFunction) C_Vector_Linspace, METH_VARARGS | METH_CLASS, C_Vector_Linspace_doc},
+ {"Repeat", (PyCFunction) C_Vector_Repeat, METH_VARARGS | METH_CLASS, C_Vector_Repeat_doc},
+
/* in place only */
{"zero", (PyCFunction) Vector_zero, METH_NOARGS, Vector_zero_doc},
{"negate", (PyCFunction) Vector_negate, METH_NOARGS, Vector_negate_doc},
@@ -2250,6 +2653,8 @@ static struct PyMethodDef Vector_methods[] = {
{"normalize", (PyCFunction) Vector_normalize, METH_NOARGS, Vector_normalize_doc},
{"normalized", (PyCFunction) Vector_normalized, METH_NOARGS, Vector_normalized_doc},
+ {"resize", (PyCFunction) Vector_resize, METH_O, Vector_resize_doc},
+ {"resized", (PyCFunction) Vector_resized, METH_O, Vector_resized_doc},
{"to_2d", (PyCFunction) Vector_to_2d, METH_NOARGS, Vector_to_2d_doc},
{"resize_2d", (PyCFunction) Vector_resize_2d, METH_NOARGS, Vector_resize_2d_doc},
{"to_3d", (PyCFunction) Vector_to_3d, METH_NOARGS, Vector_to_3d_doc},
@@ -2375,7 +2780,7 @@ PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTy
{
VectorObject *self;
- if (size > 4 || size < 2) {
+ if (size < 2) {
PyErr_SetString(PyExc_RuntimeError,
"Vector(): invalid size");
return NULL;
@@ -2429,3 +2834,12 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, int cb_type, int
return (PyObject *)self;
}
+
+PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type)
+{
+ VectorObject *vect_ob;
+ vect_ob= (VectorObject *)Vector_CreatePyObject(vec, size, Py_WRAP, base_type);
+ vect_ob->wrapped= Py_NEW;
+
+ return (PyObject *)vect_ob;
+}
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 0f7fa174d18..4e10e795602 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -41,11 +41,12 @@ extern PyTypeObject vector_Type;
typedef struct {
BASE_MATH_MEMBERS(vec);
- unsigned char size; /* vec size 2,3 or 4 */
+ int size; /* vec size 2,3 or 4 */
} VectorObject;
/*prototypes*/
PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTypeObject *base_type);
PyObject *Vector_CreatePyObject_cb(PyObject *user, int size, int callback_type, int subtype);
+PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type);
#endif /* MATHUTILS_VECTOR_H */