cleanup for mathutils multiplication functions, a little faster in some cases, raise...
authorCampbell Barton <ideasman42@gmail.com>
Sun, 9 Jan 2011 09:16:04 +0000 (09:16 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 9 Jan 2011 09:16:04 +0000 (09:16 +0000)
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector.c
source/blender/python/generic/mathutils_matrix.c
source/blender/python/generic/mathutils_quat.c
source/blender/python/generic/mathutils_vector.c

index 5f6251bf3824898c64ec1bd5a241538f09f41563..43cf612c33c5a3e350cb45e9ec5e3fcfe9c18f3a 100644 (file)
@@ -175,6 +175,8 @@ void range_vni(int *array, const int size, const int start);
 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_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 2ff1e948317d4b8876a978dc69d752be3977042b..539d3fb97f68ea8373d93c4d36a8fb7860f74f45 100644 (file)
@@ -398,6 +398,24 @@ void add_vn_vn(float *array_tar, const float *array_src, const int size)
        while(i--) { *(tar--) += *(src--); }
 }
 
+void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const int size)
+{
+       float *tar= array_tar + (size-1);
+       const float *src_a= array_src_a + (size-1);
+       const float *src_b= array_src_b + (size-1);
+       int i= size;
+       while(i--) { *(tar--) = *(src_a--) + *(src_b--); }
+}
+
+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);
+       const float *src_a= array_src_a + (size-1);
+       const float *src_b= array_src_b + (size-1);
+       int i= size;
+       while(i--) { *(tar--) = *(src_a--) - *(src_b--); }
+}
+
 void fill_vni(int *array_tar, const int size, const int val)
 {
        int *tar= array_tar + (size-1);
index b67d4c54a7d7221a14cd41c1e06759fa37525a7a..df176d4f18d5f05799bb166d267363e86d14d736 100644 (file)
@@ -1498,9 +1498,7 @@ static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject *
   ------------------------obj + obj------------------------------*/
 static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
 {
-       int x, y;
-       float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+       float mat[16];
        MatrixObject *mat1 = NULL, *mat2 = NULL;
 
        mat1 = (MatrixObject*)m1;
@@ -1519,21 +1517,15 @@ static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
                return NULL;
        }
 
-       for(x = 0; x < mat1->rowSize; x++) {
-               for(y = 0; y < mat1->colSize; y++) {
-                       mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
-               }
-       }
+       add_vn_vnvn(mat, mat1->contigPtr, mat2->contigPtr, mat1->rowSize * mat1->colSize);
 
-       return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
+       return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, Py_TYPE(mat1));
 }
 /*------------------------obj - obj------------------------------
   subtraction*/
 static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
 {
-       int x, y;
-       float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+       float mat[16];
        MatrixObject *mat1 = NULL, *mat2 = NULL;
 
        mat1 = (MatrixObject*)m1;
@@ -1552,23 +1544,23 @@ static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
                return NULL;
        }
 
-       for(x = 0; x < mat1->rowSize; x++) {
-               for(y = 0; y < mat1->colSize; y++) {
-                       mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
-               }
-       }
+       sub_vn_vnvn(mat, mat1->contigPtr, mat2->contigPtr, mat1->rowSize * mat1->colSize);
 
-       return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
+       return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, Py_TYPE(mat1));
 }
 /*------------------------obj * obj------------------------------
   mulplication*/
+static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
+{
+       float tmat[16];
+       mul_vn_vn_fl(tmat, mat->contigPtr, mat->rowSize * mat->colSize, scalar);
+       return newMatrixObject(tmat, mat->rowSize, mat->colSize, Py_NEW, Py_TYPE(mat));
+}
+
 static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
 {
-       int x, y, z;
        float scalar;
-       float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-       double dot = 0.0f;
+
        MatrixObject *mat1 = NULL, *mat2 = NULL;
 
        if(MatrixObject_Check(m1)) {
@@ -1587,54 +1579,42 @@ static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
                        PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize");
                        return NULL;
                }
-               for(x = 0; x < mat2->rowSize; x++) {
-                       for(y = 0; y < mat1->colSize; y++) {
-                               for(z = 0; z < mat1->rowSize; z++) {
-                                       dot += (mat1->matrix[z][y] * mat2->matrix[x][z]);
-                               }
-                               mat[((x * mat1->colSize) + y)] = (float)dot;
-                               dot = 0.0f;
-                       }
-               }
-               
-               return newMatrixObject(mat, mat2->rowSize, mat1->colSize, Py_NEW, Py_TYPE(mat1));
-       }
-       
-       if(mat1==NULL){
-               scalar=PyFloat_AsDouble(m1); // may not be a float
-               if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */
+               else {
+                       float mat[16]= {0.0f, 0.0f, 0.0f, 0.0f,
+                                                       0.0f, 0.0f, 0.0f, 0.0f,
+                                                       0.0f, 0.0f, 0.0f, 0.0f,
+                                                       0.0f, 0.0f, 0.0f, 1.0f};
+                       double dot = 0.0f;
+                       int x, y, z;
+
                        for(x = 0; x < mat2->rowSize; x++) {
-                               for(y = 0; y < mat2->colSize; y++) {
-                                       mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
+                               for(y = 0; y < mat1->colSize; y++) {
+                                       for(z = 0; z < mat1->rowSize; z++) {
+                                               dot += (mat1->matrix[z][y] * mat2->matrix[x][z]);
+                                       }
+                                       mat[((x * mat1->colSize) + y)] = (float)dot;
+                                       dot = 0.0f;
                                }
                        }
-                       return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, Py_TYPE(mat2));
+
+                       return newMatrixObject(mat, mat2->rowSize, mat1->colSize, Py_NEW, Py_TYPE(mat1));
                }
-               
-               PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
-               return NULL;
        }
-       else /* if(mat1) { */ {
-               if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */
-                       PyErr_SetString(PyExc_TypeError, "Matrix multiplication: Only 'vec * matrix' is supported, not the reverse");
-                       return NULL;
+       else if(mat2) {
+               if (((scalar= PyFloat_AsDouble(m1)) == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX */
+                       return matrix_mul_float(mat2, scalar);
                }
-               else {
-                       scalar= PyFloat_AsDouble(m2);
-                       if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */
-                               for(x = 0; x < mat1->rowSize; x++) {
-                                       for(y = 0; y < mat1->colSize; y++) {
-                                               mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
-                                       }
-                               }
-                               return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, Py_TYPE(mat1));
-                       }
+       }
+       else if(mat1) {
+               if (((scalar= PyFloat_AsDouble(m2)) == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX */
+                       return matrix_mul_float(mat1, scalar);
                }
-               PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
-               return NULL;
+       }
+       else {
+               BKE_assert(!"internal error");
        }
 
-       PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
+       PyErr_Format(PyExc_TypeError, "Matrix multiplication: not supported between '%.200s' and '%.200s' types", Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
        return NULL;
 }
 static PyObject* Matrix_inv(MatrixObject *self)
index 36fb0ad66bdd7cc7f60b05831c8bb28f484eed4a..1de249205b2177a8745f4d3dd1a9b92f0adf00f8 100644 (file)
@@ -641,6 +641,15 @@ static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
 
        return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1));
 }
+
+static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
+{
+       float tquat[4];
+       copy_qt_qt(tquat, quat->quat);
+       mul_qt_fl(tquat, scalar);
+       return newQuaternionObject(tquat, Py_NEW, Py_TYPE(quat));
+}
+
 //------------------------obj * obj------------------------------
 //mulplication
 static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
@@ -663,33 +672,22 @@ static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
                mul_qt_qtqt(quat, quat1->quat, quat2->quat);
                return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1));
        }
-       
        /* the only case this can happen (for a supported type is "FLOAT*QUAT" ) */
-       if(!QuaternionObject_Check(q1)) {
-               scalar= PyFloat_AsDouble(q1);
-               if ((scalar == -1.0 && PyErr_Occurred())==0) { /* FLOAT*QUAT */
-                       QUATCOPY(quat, quat2->quat);
-                       mul_qt_fl(quat, scalar);
-                       return newQuaternionObject(quat, Py_NEW, Py_TYPE(q2));
+       else if(quat2) { /* FLOAT*QUAT */
+               if(((scalar= PyFloat_AsDouble(q1)) == -1.0 && PyErr_Occurred())==0) {
+                       return quat_mul_float(quat2, scalar);
                }
-               PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: val * quat, val is not an acceptable type");
-               return NULL;
        }
-       else { /* QUAT*SOMETHING */
-               if(VectorObject_Check(q2)){  /* QUAT*VEC */
-                       PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: Only 'vector * quaternion' is supported, not the reverse");
-                       return NULL;
-               }
-               
-               scalar= PyFloat_AsDouble(q2);
-               if ((scalar == -1.0 && PyErr_Occurred())==0) { /* QUAT*FLOAT */
-                       QUATCOPY(quat, quat1->quat);
-                       mul_qt_fl(quat, scalar);
-                       return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1));
+       else if (quat1) { /* QUAT*FLOAT */
+               if((((scalar= PyFloat_AsDouble(q2)) == -1.0 && PyErr_Occurred())==0)) {
+                       return quat_mul_float(quat1, scalar);
                }
        }
-       
-       PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: arguments not acceptable for this operation");
+       else {
+               BKE_assert(!"internal error");
+       }
+
+       PyErr_Format(PyExc_TypeError, "Quaternion multiplication: not supported between '%.200s' and '%.200s' types", Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
        return NULL;
 }
 
index 3d80f6bade4da5ea8366d5c98f4cb47e7e13e3c5..2208046e6c0dbae28827db83596536f7fd641299 100644 (file)
@@ -1047,6 +1047,17 @@ static int column_vector_multiplication(float *rvec, VectorObject* vec, MatrixOb
        return 0;
 }
 
+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;
+       }
+       return newVectorObject(tvec, vec->size, Py_NEW, Py_TYPE(vec));
+}
+
 static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
 {
        VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1080,55 +1091,48 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
                }
                return PyFloat_FromDouble(dot);
        }
-       
-       /* swap so vec1 is always the vector */
-       /* note: it would seem from this code that the matrix multiplication below
-        * is communicative. however the matrix class will always handle the
-        * (matrix * vector) case so we can ignore it here.
-        * This is NOT so for Quaternions: TODO, check if communicative (vec * quat) is correct */
-       if (vec2) {
-               vec1= vec2;
-               v2= v1;
-       }
+       else if (vec1) {
+               if (MatrixObject_Check(v2)) {
+                       /* VEC * MATRIX */
+                       float tvec[MAX_DIMENSIONS];
+                       if(!BaseMath_ReadCallback((MatrixObject *)v2))
+                               return NULL;
+                       if(column_vector_multiplication(tvec, vec1, (MatrixObject*)v2) == -1) {
+                               return NULL;
+                       }
 
-       if (MatrixObject_Check(v2)) {
-               /* VEC * MATRIX */
-               float tvec[MAX_DIMENSIONS];
-               if(!BaseMath_ReadCallback((MatrixObject *)v2))
-                       return NULL;
-               if(column_vector_multiplication(tvec, vec1, (MatrixObject*)v2) == -1) {
-                       return NULL;
+                       return newVectorObject(tvec, vec1->size, Py_NEW, Py_TYPE(vec1));
                }
+               else if (QuaternionObject_Check(v2)) {
+                       /* VEC * QUAT */
+                       QuaternionObject *quat2 = (QuaternionObject*)v2;
+                       float tvec[3];
 
-               return newVectorObject(tvec, vec1->size, Py_NEW, Py_TYPE(vec1));
-       } else if (QuaternionObject_Check(v2)) {
-               /* VEC * QUAT */
-               QuaternionObject *quat2 = (QuaternionObject*)v2;
-               float tvec[3];
-
-               if(vec1->size != 3) {
-                       PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported");
-                       return NULL;
+                       if(vec1->size != 3) {
+                               PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported");
+                               return NULL;
+                       }
+                       if(!BaseMath_ReadCallback(quat2)) {
+                               return NULL;
+                       }
+                       copy_v3_v3(tvec, vec1->vec);
+                       mul_qt_v3(quat2->quat, tvec);
+                       return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(vec1));
                }
-               if(!BaseMath_ReadCallback(quat2)) {
-                       return NULL;
+               else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */
+                       return vector_mul_float(vec1, scalar);
                }
-               copy_v3_v3(tvec, vec1->vec);
-               mul_qt_v3(quat2->quat, tvec);
-               return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(vec1));
        }
-       else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */
-               int i;
-               float vec[MAX_DIMENSIONS];
-               
-               for(i = 0; i < vec1->size; i++) {
-                       vec[i] = vec1->vec[i] * scalar;
+       else if (vec2) {
+               if (((scalar= PyFloat_AsDouble(v1)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */
+                       return vector_mul_float(vec2, scalar);
                }
-               return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(vec1));
-               
        }
-       
-       PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation");
+       else {
+               BKE_assert(!"internal error");
+       }
+
+       PyErr_Format(PyExc_TypeError, "Vector multiplication: not supported between '%.200s' and '%.200s' types", Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
        return NULL;
 }