Reputation: 313
I am a little confused on how exactly postScale method calculates the values of matrix. Here is the code:
Matrix m1 = new Matrix();
float[] values = { 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f };
m1.setValues(values);
Matrix m2 = new Matrix(m1);
m1.preScale(2f, 3f); //result: 2, 6, 3, 8, 15, 6, 14, 24, 9
m2.postScale(2f, 3f); //result: 1, 2, 3, 6, 7.5, 9, 3.5, 4, 4.5
Documentation says that the result of preScale is (Matrix * scale) and the result of postScale is (scale * Matrix). But the results vary if I calculate the matrices manually.
multiply from right:
1 2 3 | 2 0 0 2 6 3
4 5 6 | 0 3 0 = 8 15 6
7 8 9 | 0 0 1 14 24 9
multiply from left:
2 0 0 | 1 2 3 2 4 6
0 3 0 | 4 5 6 = 12 15 18
0 0 1 | 7 8 9 7 8 9
...left multiplication (postScale) returns a different result than I expected.
I even looked into the native implementation (Matrix_Delegate.java). But I don't know where the problem is. Is there something I'm missing?
Upvotes: 3
Views: 3214
Reputation: 4203
After setConcat (in android/external/skia/src/core/SkMatrix.cpp ) multiples two matrices of which at least one is a perspective matrix, it calls a method called "normalize_perspective". If the last cell of the matrix (the bottom right corner, mat[2][2] if zero-indexed, mat[8] in this representation) is greater than 1, it divides every number in the matrix by two. That certainly describes what we're seeing here.
But how does our friendly matrix come to be considered a perspective matrix? Well. When we do setValues(), the type gets set as Unknown. When setConcat calls getType, it sees "unknown" and decides to do something about that. It calls computeTypeMask. computeTypeMask looks at the third column, sees that it's not [ 0 0 1 ], and slaps a Perspective label on the type of the matrix. This happens to your m2.
But why is all this only an issue for postScale? preScale (unless the Skia library is compiled in fixed-point mode) does the scaling itself, so it never gets into setConcat to strike upon these rocky shoals.
Why is normalize_perspective a good idea? Damned if I know. It's probably something to do with the expected 2d graphics applications for these particular routines.
What can you do about all this? If you're targeting API level 11 or greater, then renderscript's Matrix3f is probably your friend. If not, I'm sorry, D-Fox, your matrix implementation is in another castle.
Upvotes: 2