From a34f525a21eff2ec1f5691ce3ec2056408bacd5d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Nov 2010 01:38:18 +0000 Subject: bugfix [#24660] (vector * matrix) fails, (matrix * vector) succeeds - Reverse vector * matrix multiplication order. now this matches how numpy works. - Disallow 'matrix * vec' and 'quat * vec', now it raises an error. - Add missing in-place multiply 'vec *= quat' Many scripts will need to be updated for this but at least it will error rather then failing silently. --- source/blender/python/generic/mathutils_matrix.c | 45 +----------- source/blender/python/generic/mathutils_quat.c | 16 +---- source/blender/python/generic/mathutils_vector.c | 90 +++++++++++++++++++----- 3 files changed, 75 insertions(+), 76 deletions(-) (limited to 'source/blender/python') diff --git a/source/blender/python/generic/mathutils_matrix.c b/source/blender/python/generic/mathutils_matrix.c index c74ec3536e5..4c481e799e2 100644 --- a/source/blender/python/generic/mathutils_matrix.c +++ b/source/blender/python/generic/mathutils_matrix.c @@ -31,9 +31,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" -static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */ - - /* matrix vector callbacks */ int mathutils_matrix_vector_cb_index= -1; @@ -1568,7 +1565,8 @@ static PyObject *Matrix_mul(PyObject * m1, PyObject * m2) } else /* if(mat1) { */ { if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */ - return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */ + PyErr_SetString(PyExc_TypeError, "Matrix multiplication: Only 'vec * matrix' is supported, not the reverse."); + return NULL; } else { scalar= PyFloat_AsDouble(m2); @@ -1945,42 +1943,3 @@ PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb } return (PyObject *) self; } - -//----------------column_vector_multiplication (internal)--------- -//COLUMN VECTOR Multiplication (Matrix X Vector) -// [1][4][7] [a] -// [2][5][8] * [b] -// [3][6][9] [c] -//vector/matrix multiplication IS NOT COMMUTATIVE!!!! -static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec) -{ - float vecNew[4], vecCopy[4]; - double dot = 0.0f; - int x, y, z = 0; - - if(!BaseMath_ReadCallback(mat) || !BaseMath_ReadCallback(vec)) - return NULL; - - 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"); - return NULL; - }else{ - vecCopy[3] = 1.0f; - } - } - - for(x = 0; x < vec->size; x++){ - vecCopy[x] = vec->vec[x]; - } - vecNew[3] = 1.0f; - - for(x = 0; x < mat->colSize; x++) { - for(y = 0; y < mat->rowSize; y++) { - dot += mat->matrix[y][x] * vecCopy[y]; - } - vecNew[z++] = (float)dot; - dot = 0.0f; - } - return newVectorObject(vecNew, vec->size, Py_NEW, NULL); -} diff --git a/source/blender/python/generic/mathutils_quat.c b/source/blender/python/generic/mathutils_quat.c index cb6e6fd3ddd..8a42adce9a9 100644 --- a/source/blender/python/generic/mathutils_quat.c +++ b/source/blender/python/generic/mathutils_quat.c @@ -647,7 +647,6 @@ static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2) { float quat[QUAT_SIZE], scalar; QuaternionObject *quat1 = NULL, *quat2 = NULL; - VectorObject *vec = NULL; if(QuaternionObject_Check(q1)) { quat1 = (QuaternionObject*)q1; @@ -678,19 +677,8 @@ static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2) } else { /* QUAT*SOMETHING */ if(VectorObject_Check(q2)){ /* QUAT*VEC */ - float tvec[3]; - vec = (VectorObject*)q2; - if(vec->size != 3){ - PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n"); - return NULL; - } - if(!BaseMath_ReadCallback(vec)) { - return NULL; - } - - copy_v3_v3(tvec, vec->vec); - mul_qt_v3(quat1->quat, tvec); - return newVectorObject(tvec, 3, Py_NEW, NULL); + PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: Only 'vector * quaternion' is supported, not the reverse"); + return NULL; } scalar= PyFloat_AsDouble(q2); diff --git a/source/blender/python/generic/mathutils_vector.c b/source/blender/python/generic/mathutils_vector.c index 57d7ee659d5..2224193914d 100644 --- a/source/blender/python/generic/mathutils_vector.c +++ b/source/blender/python/generic/mathutils_vector.c @@ -39,7 +39,6 @@ #define SWIZZLE_VALID_AXIS 0x4 #define SWIZZLE_AXIS 0x3 -static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObject * mat); /* utility func */ static PyObject *Vector_ToTupleExt(VectorObject *self, int ndigits); //----------------------------------mathutils.Vector() ------------------ @@ -1007,6 +1006,47 @@ static PyObject *Vector_isub(PyObject * v1, PyObject * v2) /*------------------------obj * obj------------------------------ mulplication*/ + + +/* COLUMN VECTOR Multiplication (Vector X Matrix) + * [a] * [1][4][7] + * [b] * [2][5][8] + * [c] * [3][6][9] + * + * 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) +{ + float vecCopy[4]; + 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"); + return -1; + }else{ + vecCopy[3] = 1.0f; + } + } + + for(x = 0; x < vec->size; x++){ + vecCopy[x] = vec->vec[x]; + } + 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]; + } + rvec[z++] = (float)dot; + dot = 0.0f; + } + + return 0; +} + static PyObject *Vector_mul(PyObject * v1, PyObject * v2) { VectorObject *vec1 = NULL, *vec2 = NULL; @@ -1050,17 +1090,21 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2) vec1= vec2; v2= v1; } - + if (MatrixObject_Check(v2)) { /* VEC * MATRIX */ - float tvec[4]; - if(row_vector_multiplication(tvec, vec1, (MatrixObject*)v2) == -1) + float tvec[MAX_DIMENSIONS]; + if(!BaseMath_ReadCallback((MatrixObject *)v2)) return NULL; - return newVectorObject(tvec, vec1->size, Py_NEW, NULL); + if(column_vector_multiplication(tvec, vec1, (MatrixObject*)v2) == -1) { + return NULL; + } + + return newVectorObject(tvec, 3, Py_NEW, NULL); } else if (QuaternionObject_Check(v2)) { /* VEC * QUAT */ QuaternionObject *quat2 = (QuaternionObject*)v2; - float tvec[4]; + float tvec[3]; if(vec1->size != 3) { PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported\n"); @@ -1075,7 +1119,7 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2) } else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */ int i; - float vec[4]; + float vec[MAX_DIMENSIONS]; for(i = 0; i < vec1->size; i++) { vec[i] = vec1->vec[i] * scalar; @@ -1093,7 +1137,6 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2) static PyObject *Vector_imul(PyObject * v1, PyObject * v2) { VectorObject *vec = (VectorObject *)v1; - int i; float scalar; if(!BaseMath_ReadCallback(vec)) @@ -1102,20 +1145,28 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2) /* only support vec*=float and vec*=mat vec*=vec result is a float so that wont work */ if (MatrixObject_Check(v2)) { - float tvec[4]; - if(row_vector_multiplication(tvec, vec, (MatrixObject*)v2) == -1) + if(!BaseMath_ReadCallback((MatrixObject *)v2)) return NULL; + + if(column_vector_multiplication(vec->vec, vec, (MatrixObject*)v2) == -1) + return NULL; + } + else if (QuaternionObject_Check(v2)) { + /* VEC *= QUAT */ + QuaternionObject *quat2 = (QuaternionObject*)v2; - i= vec->size - 1; - do { - vec->vec[i] = tvec[i]; - } while(i--); + if(vec->size != 3) { + PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported\n"); + return NULL; + } + + if(!BaseMath_ReadCallback(quat2)) { + return NULL; + } + mul_qt_v3(quat2->quat, vec->vec); } else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */ - i= vec->size - 1; - do { - vec->vec[i] *= scalar; - } while(i--); + mul_vn_fl(vec->vec, vec->size, scalar); } else { PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n"); @@ -2010,7 +2061,7 @@ if len(unique) != len(items): print "ERROR" */ -//-----------------row_vector_multiplication (internal)----------- +#if 0 //ROW VECTOR Multiplication - Vector X Matrix //[x][y][z] * [1][4][7] // [2][5][8] @@ -2048,6 +2099,7 @@ static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObj } return 0; } +#endif /*----------------------------Vector.negate() -------------------- */ static char Vector_Negate_doc[] = -- cgit v1.2.3