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.
This commit is contained in:
Campbell Barton 2010-11-12 01:38:18 +00:00
parent 44e36b5156
commit a34f525a21
3 changed files with 75 additions and 76 deletions

@ -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);
}

@ -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);

@ -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[] =