forked from bartvdbraak/blender
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:
parent
44e36b5156
commit
a34f525a21
@ -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;
|
||||
@ -1053,14 +1093,18 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
|
||||
|
||||
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;
|
||||
|
||||
i= vec->size - 1;
|
||||
do {
|
||||
vec->vec[i] = tvec[i];
|
||||
} while(i--);
|
||||
if(column_vector_multiplication(vec->vec, vec, (MatrixObject*)v2) == -1)
|
||||
return NULL;
|
||||
}
|
||||
else if (QuaternionObject_Check(v2)) {
|
||||
/* VEC *= QUAT */
|
||||
QuaternionObject *quat2 = (QuaternionObject*)v2;
|
||||
|
||||
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[] =
|
||||
|
Loading…
Reference in New Issue
Block a user