美文网首页
Matrix源码解析

Matrix源码解析

作者: 扎实基础cc | 来源:发表于2016-08-02 18:28 被阅读544次

正文之前

这两天看了深入理解 Android 中的 MatrixMatrix原理。这两篇文章写的都挺好的,但是我看完了,还有一些地方没明白,所以今天就好好看了一下native层的源代码。我始终觉得源码是解答很多问题的最好途径。

Matrix

首先看一下官方对Matrix的解释:

The Matrix class holds a 3x3 matrix for transforming coordinates.

从解释可知Matrix是一个3x3的矩阵。矩阵的每一个位置的值是干什么的呢?这一个疑问。那么就从他的用途来找答案

preXXX和postXXX源码解读

preTranslate为例解答上面的疑问。来看一下上层的preTranslate源码:

   /**
    * Preconcats the matrix with the specified translation.
    * M' = M * T(dx, dy)
    */
    public boolean preTranslate(float dx, float dy) {
        native_preTranslate(native_instance, dx, dy);
        return true;
    }

param dx,dy分别是x,y方向的位移。调用了native层的native_preTranslate

386 static void native_preTranslate(long native_object, float dx, float dy) {
387        Matrix_Delegate d = sManager.getDelegate(native_object);
388        if (d != null) {
389            d.preTransform(getTranslate(dx, dy));
390        }
391    }

先看getTranslate(dx, dy)

952    /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) {
953        dest[0] = 1;
954        dest[1] = 0;
955        dest[2] = dx;
956        dest[3] = 0;
957        dest[4] = 1;
958        dest[5] = dy;
959        dest[6] = 0;
960        dest[7] = 0;
961        dest[8] = 1;
962        return dest;
963    }

这里构造了一个数组或者说是一个3x3的矩阵,然后将dx,dy放到特定的位置。然后返回的结果是:

Paste_Image.png

仔细观察其他几个preXX,他们最终都会调用preTransform

preTransform源码:

831    /**
832     * Adds the given transformation to the current Matrix
833     * <p/>This in effect does this = matrix*this
834     * @param matrix
835     */
836    private void preTransform(float[] matrix) {
837        float[] tmp = new float[9];
838        multiply(tmp, matrix, mValues);
839        mValues = tmp;
840    }

代码思路很简单,先调用multiply(tmp, matrix, mValues);计算矩阵相乘的结果,然后把结果再赋给mValues矩阵。

其实矩阵相乘本身是个数学问题,而且很简单,但是我还是想列出来,因为这里我认为作者在写注释的时候并没有注意左乘和右乘在写法上的区别,以至于在上层api的代码中对左乘和右乘的解释中,pre、postpost与native层中的pre、post是相反的。

920    /**
921     * multiply two matrices and store them in a 3rd.
922     * <p/>This in effect does dest = a*b
923     * dest cannot be the same as a or b.
924     */
925     /*package*/ static void multiply(float dest[], float[] a, float[] b) {
926        // first row
927        dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
928        dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
929        dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8];
930
931        // 2nd row
932        dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6];
933        dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7];
934        dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8];
935
936        // 3rd row
937        dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6];
938        dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7];
939        dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8];
940    }

从代码中很明显的能看出作者想计算的应该是ba而不是ab**。这样就导致了在上层中对于操作的解释不同:

native层对pre的解释:

/ * Adds the given transformation to the current Matrix
 * <p/>This in effect does this = matrix*this
 * @param matrix
 */

上层api对pre的解释:

/ * Preconcats the matrix with the specified translation.
 * M' = M * T(dx, dy)
 */

其他几个操作需要构造的矩阵如下:

这里读者可以仔细揣摩一下。

我认为引入3x3矩阵的好处是: 把三种操作归并到矩阵相乘

post操作只不过是吧mValues和构造出的矩阵在作为参数传入multiply的时候交换了位置。

几种操作对应需要构造的矩阵:

965    /*package*/ static float[] getScale(float sx, float sy) {
966        return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
967    }

1015    /*package*/ static float[] setRotate(float[] dest, float sin, float cos) {
1016        dest[0] = cos;
1017        dest[1] = -sin;
1018        dest[2] = 0;
1019        dest[3] = sin;
1020        dest[4] = cos;
1021        dest[5] = 0;
1022        dest[6] = 0;
1023        dest[7] = 0;
1024        dest[8] = 1;
1025        return dest;
1026    }

1049    /*package*/ static float[] getSkew(float kx, float ky) {
1050        return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
1051    }
Paste_Image.png Paste_Image.png

把四种情况综合起来:


Paste_Image.png

这种情况下pre和post操作的结果是一样的。

需要说明的是,虽然看上去pre和post操作可以写成矩阵链相乘的形式,但是实际上还是按照出现的先后顺序计算的。

相关文章

网友评论

      本文标题:Matrix源码解析

      本文链接:https://www.haomeiwen.com/subject/junfsttx.html