bugfix + minor mathutils.Vector edits.
authorCampbell Barton <ideasman42@gmail.com>
Sun, 23 Jan 2011 08:37:34 +0000 (08:37 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 23 Jan 2011 08:37:34 +0000 (08:37 +0000)
- multiplying a 2D vector by a 3x3 or 4x4 matrix would use un-initialized memory, now throw an exception.
- use more variable length array BLI_math functions.

source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector.c
source/blender/python/generic/mathutils_vector.c
source/blender/python/generic/mathutils_vector.h

index 35b7939329aa2e002612ddbf8e13cd101f7f5406..5a5d518940d18b42d2561878ca0045671bf4c3ea 100644 (file)
@@ -176,6 +176,7 @@ void mul_vn_fl(float *array, const int size, const float f);
 void mul_vn_vn_fl(float *array_tar, const float *array_src, const int size, const float f);
 void add_vn_vn(float *array_tar, const float *array_src, const int size);
 void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const int size);
+void sub_vn_vn(float *array_tar, const float *array_src, const int size);
 void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const int size);
 void fill_vni(int *array_tar, const int size, const int val);
 void fill_vn(float *array_tar, const int size, const float val);
index 539d3fb97f68ea8373d93c4d36a8fb7860f74f45..37a68cb0fca65bb3e4aaaf24d40e0f4906df3c92 100644 (file)
@@ -407,6 +407,14 @@ void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_
        while(i--) { *(tar--) = *(src_a--) + *(src_b--); }
 }
 
+void sub_vn_vn(float *array_tar, const float *array_src, const int size)
+{
+       float *tar= array_tar + (size-1);
+       const float *src= array_src + (size-1);
+       int i= size;
+       while(i--) { *(tar--) -= *(src--); }
+}
+
 void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const int size)
 {
        float *tar= array_tar + (size-1);
index a3bf14718133f92a19a5ed63c0ea3fc2f0c17d70..de6002859d35e63a09d137f9adf625b43f8e4331 100644 (file)
@@ -76,11 +76,8 @@ static char Vector_Zero_doc[] =
 
 static PyObject *Vector_Zero(VectorObject *self)
 {
-       int i;
-       for(i = 0; i < self->size; i++) {
-               self->vec[i] = 0.0f;
-       }
-       
+       fill_vn(self->vec, self->size, 0.0f);
+
        (void)BaseMath_WriteCallback(self);
        Py_INCREF(self);
        return (PyObject*)self;
@@ -780,7 +777,6 @@ static PyObject *Vector_item(VectorObject *self, int i)
                return NULL;
        
        return PyFloat_FromDouble(self->vec[i]);
-
 }
 /*----------------------------object[]-------------------------
   sequence accessor (set)*/
@@ -861,43 +857,34 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end,
   addition*/
 static PyObject *Vector_add(PyObject * v1, PyObject * v2)
 {
-       int i;
-       float vec[4];
-
        VectorObject *vec1 = NULL, *vec2 = NULL;
-       
-       if VectorObject_Check(v1)
-               vec1= (VectorObject *)v1;
-       
-       if VectorObject_Check(v2)
-               vec2= (VectorObject *)v2;
-       
-       /* make sure v1 is always the vector */
-       if (vec1 && vec2 ) {
-               
-               if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
-                       return NULL;
-               
-               /*VECTOR + VECTOR*/
-               if(vec1->size != vec2->size) {
-                       PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation");
-                       return NULL;
-               }
-               for(i = 0; i < vec1->size; i++) {
-                       vec[i] = vec1->vec[i] + vec2->vec[i];
-               }
-               return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
+       float vec[MAX_DIMENSIONS];
+
+       if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
+               PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation");
+               return NULL;
        }
-       
-       PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation");
-       return NULL;
+       vec1 = (VectorObject*)v1;
+       vec2 = (VectorObject*)v2;
+
+       if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
+               return NULL;
+
+       /*VECTOR + VECTOR*/
+       if(vec1->size != vec2->size) {
+               PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation");
+               return NULL;
+       }
+
+       add_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size);
+
+       return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
 }
 
 /*  ------------------------obj += obj------------------------------
   addition in place */
 static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
 {
-       int i;
        VectorObject *vec1 = NULL, *vec2 = NULL;
 
        if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
@@ -915,12 +902,10 @@ static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
        if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
                return NULL;
 
-       for(i = 0; i < vec1->size; i++) {
-               vec1->vec[i] = vec1->vec[i] + vec2->vec[i];
-       }
+       add_vn_vn(vec1->vec, vec2->vec, vec1->size);
 
        (void)BaseMath_WriteCallback(vec1);
-       Py_INCREF( v1 );
+       Py_INCREF(v1);
        return v1;
 }
 
@@ -928,9 +913,8 @@ static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
   subtraction*/
 static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
 {
-       int i;
-       float vec[4];
        VectorObject *vec1 = NULL, *vec2 = NULL;
+       float vec[MAX_DIMENSIONS];
 
        if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
                PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation");
@@ -946,9 +930,8 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
                PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation");
                return NULL;
        }
-       for(i = 0; i < vec1->size; i++) {
-               vec[i] = vec1->vec[i] - vec2->vec[i];
-       }
+
+       sub_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size);
 
        return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
 }
@@ -957,8 +940,7 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
   subtraction*/
 static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
 {
-       int i;
-       VectorObject *vec1 = NULL, *vec2 = NULL;
+       VectorObject *vec1= NULL, *vec2= NULL;
 
        if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
                PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation");
@@ -975,12 +957,10 @@ static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
        if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
                return NULL;
 
-       for(i = 0; i < vec1->size; i++) {
-               vec1->vec[i] = vec1->vec[i] -   vec2->vec[i];
-       }
+       sub_vn_vn(vec1->vec, vec2->vec, vec1->size);
 
        (void)BaseMath_WriteCallback(vec1);
-       Py_INCREF( v1 );
+       Py_INCREF(v1);
        return v1;
 }
 
@@ -996,29 +976,29 @@ static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
  * note: vector/matrix multiplication IS NOT COMMUTATIVE!!!!
  * note: assume read callbacks have been done first.
  */
-static int column_vector_multiplication(float *rvec, VectorObject* vec, MatrixObject * mat)
+static int column_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject* vec, MatrixObject * mat)
 {
-       float vecCopy[4];
+       float vec_cpy[MAX_DIMENSIONS];
        double dot = 0.0f;
        int x, y, z = 0;
        
        if(mat->rowSize != vec->size){
-               if(mat->rowSize == 4 && vec->size != 3){
-                       PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same");
+               if(mat->rowSize == 4 && vec->size == 3) {
+                       vec_cpy[3] = 1.0f;
+               }
+               else {
+                       PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix.row_size and len(vector) must be the same, except for 3D vector * 4x4 matrix.");
                        return -1;
-               }else{
-                       vecCopy[3] = 1.0f;
                }
        }
 
-       for(x = 0; x < vec->size; x++){
-               vecCopy[x] = vec->vec[x];
-       }
+       memcpy(vec_cpy, vec->vec, vec->size * sizeof(float));
+
        rvec[3] = 1.0f;
 
        for(x = 0; x < mat->colSize; x++) {
                for(y = 0; y < mat->rowSize; y++) {
-                       dot += mat->matrix[y][x] * vecCopy[y];
+                       dot += mat->matrix[y][x] * vec_cpy[y];
                }
                rvec[z++] = (float)dot;
                dot = 0.0f;
@@ -1030,11 +1010,7 @@ static int column_vector_multiplication(float *rvec, VectorObject* vec, MatrixOb
 static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
 {
        float tvec[MAX_DIMENSIONS];
-       int i;
-
-       for(i = 0; i < vec->size; i++) {
-               tvec[i] = vec->vec[i] * scalar;
-       }
+       mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar);
        return newVectorObject(tvec, vec->size, Py_NEW, Py_TYPE(vec));
 }
 
@@ -1493,7 +1469,7 @@ static PyObject *Vector_getLength(VectorObject *self, void *UNUSED(closure))
        return PyFloat_FromDouble(sqrt(dot));
 }
 
-static int Vector_setLength(VectorObject *self, PyObject * value )
+static int Vector_setLength(VectorObject *self, PyObject *value)
 {
        double dot = 0.0f, param;
        int i;
@@ -1511,9 +1487,7 @@ static int Vector_setLength(VectorObject *self, PyObject * value )
                return -1;
        }
        if (param == 0.0f) {
-               for(i = 0; i < self->size; i++){
-                       self->vec[i]= 0;
-               }
+               fill_vn(self->vec, self->size, 0.0f);
                return 0;
        }
        
@@ -2052,7 +2026,7 @@ if len(unique) != len(items):
 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
 static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObject * mat)
 {
-       float vecCopy[4];
+       float vec_cpy[4];
        double dot = 0.0f;
        int x, y, z = 0, vec_size = vec->size;
 
@@ -2061,21 +2035,20 @@ static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObj
                        PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
                        return -1;
                }else{
-                       vecCopy[3] = 1.0f;
+                       vec_cpy[3] = 1.0f;
                }
        }
        
        if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat))
                return -1;
-       
-       for(x = 0; x < vec_size; x++){
-               vecCopy[x] = vec->vec[x];
-       }
+
+       memcpy(vec_cpy, vec->vec, vec_size * sizeof(float));
+
        rvec[3] = 1.0f;
        //muliplication
        for(x = 0; x < mat->rowSize; x++) {
                for(y = 0; y < mat->colSize; y++) {
-                       dot += mat->matrix[x][y] * vecCopy[y];
+                       dot += mat->matrix[x][y] * vec_cpy[y];
                }
                rvec[z++] = (float)dot;
                dot = 0.0f;
@@ -2226,9 +2199,8 @@ PyTypeObject vector_Type = {
  (i.e. it was allocated elsewhere by MEM_mallocN())
   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
  (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type)
+PyObject *newVectorObject(float *vec, const int size, const int type, PyTypeObject *base_type)
 {
-       int i;
        VectorObject *self;
 
        if(size > 4 || size < 2)
@@ -2247,16 +2219,14 @@ PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_typ
                self->vec = vec;
                self->wrapped = Py_WRAP;
        } else if (type == Py_NEW) {
-               self->vec = PyMem_Malloc(size * sizeof(float));
-               if(!vec) { /*new empty*/
-                       for(i = 0; i < size; i++){
-                               self->vec[i] = 0.0f;
-                       }
-                       if(size == 4)  /* do the homogenous thing */
+               self->vec= PyMem_Malloc(size * sizeof(float));
+               if(vec) {
+                       memcpy(self->vec, vec, size * sizeof(float));
+               }
+               else { /* new empty */
+                       fill_vn(self->vec, size, 0.0f);
+                       if(size == 4) { /* do the homogenous thing */
                                self->vec[3] = 1.0f;
-               }else{
-                       for(i = 0; i < size; i++){
-                               self->vec[i] = vec[i];
                        }
                }
                self->wrapped = Py_NEW;
index e5d15dbfdb0f5b66515f8c6c0e30789cac24f874..2dbe9d9d3fe9cf6fb889803f90f125125d1b0b6d 100644 (file)
@@ -43,7 +43,7 @@ typedef struct {
 } VectorObject;
 
 /*prototypes*/
-PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type);
+PyObject *newVectorObject(float *vec, const int size, const int type, PyTypeObject *base_type);
 PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype);
 
 #endif                         /* MATHUTILS_VECTOR_H */