Support for arbitrary sized vectors - (was limited by 2-4 previously)
authorCampbell Barton <ideasman42@gmail.com>
Sun, 18 Dec 2011 07:27:11 +0000 (07:27 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 18 Dec 2011 07:27:11 +0000 (07:27 +0000)
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.

source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector.c
source/blender/python/mathutils/mathutils.c
source/blender/python/mathutils/mathutils.h
source/blender/python/mathutils/mathutils_Vector.c
source/blender/python/mathutils/mathutils_Vector.h

index d8e880a9dec7d77ad1c11a785c6f45504ea0222b..e9e44ed7b2c5fb4334e05ccf2ab1c2c21eceab25 100644 (file)
@@ -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);
index a9ea90ef5556e02b878a5b3df456e2afac5b238d..590a48e808565f0ce43eb2aa0cfa9335bc0338cb 100644 (file)
@@ -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);
index 121c5e26e7381b1cc6f7a3859e1779739ad22689..6a7f54d6f81d4d958c2a86ee74ca48b9b51ca834 100644 (file)
@@ -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);
        }
 }
 
index a8170b8145ca2f2d54b3d2d1e0c05162c33918d0..cd3548b9b825218757e32a4a985c1309047c9b34 100644 (file)
@@ -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);
index 9d1a22adb127647705cb27d6846986211cc53cc4..a812311dad4601e88e607d75bebfec04422657e6 100644 (file)
@@ -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;
+}
index 0f7fa174d186e66fc755a6ba43f45c5837d13f96..4e10e7956023fa6f33b63d0494007ee1a578374f 100644 (file)
@@ -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 */