美文网首页自定义View
自定义View(十)Matrix 基础理论与使用

自定义View(十)Matrix 基础理论与使用

作者: 光羽隼 | 来源:发表于2018-11-20 18:48 被阅读0次

    Matrix就是矩阵的意思,所有的控件中都有Matrix的身影。

    Matrix是一个三阶矩阵,主要功能是坐标映射,数值变换,见下图

    Matrix

    再讲下边的内容之间,先提前介绍一下下边用到的名词:

    名词 解释
    单位矩阵 单位矩阵
    M 原始矩阵,没有变换之前的矩阵
    A 变换
    M` 结果矩阵
    T 平移变换
    -T 反向平移变换
    R 旋转变换

    Matrix基本原理

    Matrix的根本作用就是坐标的变化;基本变换有平移(translate),缩放(scale),旋转(skew),错切四种。


    矩阵中各数据组合所指
    矩阵中各数据组合所指

    最后一行的数据透视使用在3D变换中

    缩放(scale)

    在进行缩放的时候需要变换(MSCALE_X,MSCALE_Y)这两个值,分别作用于x和y。


    缩放
    X=K1*X0
    Y=K2*Y0
    

    错切(skew)

    错切需要变换(MSKEW_X,MSKEW_Y),分别作用于水平错切和垂直错切;


    错切
    X=X0+K1*Y0
    Y=K2*X0+Y0
    

    旋转(rotate)

    当要旋转 θ角度的时候,博客中计算了一遍,讲了下边矩阵变换数据的来历,我看了一遍也记不住,还是及这个图来的快。。。。


    旋转

    平移(translate)

    平移需要修改的是最后一列的前两个数据(MTRANS_X,MTRANS_Y),分别作用在x和y 上。


    平移

    总结

    看了上边的几种变换,其实就是对应修改单位矩阵中的特定数值。比如说,要旋转,就要修改左上角四个数值,得到变换矩阵,拿变换矩阵跟原始矩阵相乘。平移,就是修改单位矩阵中最后一列的上边两个数值,如果你只想在x轴平移,那么只需要修改最后一列的第一个数据。看了上边的东西,大概知道矩阵作用了,可是矩阵该怎么在实际代码中使用呢?一步一步来

    Matrix 矩阵复合原理

    矩阵复合有三种,前乘(pre),后乘(post),设置(set)
    为什么会有前乘和后乘的区别呢?
    因为

    矩阵乘法不满足交换律,即 AB ≠ BA
    矩阵乘法满足结合律,即 (AB)C = A(BC)
    矩阵与单位矩阵相乘结果不变,即 A * I = A

    前乘(pre)

    前乘就是原始矩阵在前边,变换矩阵在后边

    M`=M*A

    后乘(post)

    后乘就是原始矩阵在后边,变换矩阵在前边

    M`=S*A

    设置(set)

    设置不是矩阵的乘法,而是覆盖原来的矩阵,使用设置之后会对之前的操作有影响。

    几个常见的错误结论:

    1.pre 是顺序执行,post 是逆序执行
    2.pre 是先执行,而 post 是后执行

    其实前乘后乘执行的顺序,跟这句代码所在的位置没有关系。

    下边将一个远博客中的例子。
    我们想讲一个控件先平移到屏幕的中间,然后对控件做一系列缩放,错切,平移等等操作,最后我们再将控件平移回远位置。
    上面的操作我们可以使用三种方法实现:

    第一种前后两个平移全部使用前乘(pre)

    Matrix matrix=new Matrix();
    matrix.preTranslate(200,200);
    matrix.preRotate(angle);
    matrix.preTranslate(-200,-200);
    

    M`=M*T*R-T
    新实例化的矩阵就是单位矩阵,所以这里M为原始矩阵,所以上边的式子可以简化为
    M`=*T*R
    -T

    第二种前后两个平移全部使用后乘

    Matrix matrix=new Matrix();
    matrix.postTranslate(-200,-200);
    matrix.postRotate(angle);
    matrix.postTranslate(-200,-200);
    

    化简公式为M`=T*R*-T*

    混合使用前乘和后乘

    Matrix matrix = new Matrix();
    // 各种操作,旋转,缩放,错切等,可以执行多次。
    matrix.postTranslate(pivotX,pivotY);
    matrix.preTranslate(-pivotX, -pivotY);
    

    M' = TM ... -T = T ... *-T
    这种方法是为了避免两次平移被拉得太开,代码量多的话,会容易漏写。

    pre 和 post 就是用来调整乘法顺序的,由于矩阵乘法不满足交换律,所以前乘后乘的结果是不一样的。

    上面都是矩阵的基础知识的理解,到底该怎么用。下边开始总结:

    Matrix的基本使用

    先看一下Matrix的基础方法

    方法 解释
    Matrix (); 构造方法,创建一个新的矩阵,为单位矩阵
    Matrix (Matrix src); 构造方法,对src矩阵进行深拷贝,也就是创建一个跟src矩阵一毛一样的矩阵。
    equals 比较两个Matrix的数值是否相同。
    hashCode 获取Matrix的哈希值。
    toString 将Matrix转换为字符串: Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
    toShortString 将Matrix转换为短字符串: [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
    void set (Matrix src) 没有返回值,有一个参数,作用是将参数Matrix的数值复制到当前Matrix中。如果参数为空,则重置当前Matrix,相当于reset()。
    void reset () 重置当前Matrix(将当前Matrix重置为单位矩阵)。
    void setValues (float[] values) setValues的参数是浮点型的一维数组,长度需要大于9,拷贝数组中的前9位数值赋值给当前Matrix。
    void getValues (float[] values) 很显然,getValues和setValues是一对方法,参数也是浮点型的一维数组,长度需要大于9,将Matrix中的数值拷贝进参数的前9位中。

    数值计算方法

    方法 解释
    void mapPoints (float[] pts) 计算一组点基于当前Matrix变换后的位置,讲计算后的矩阵数值存放到pts数组中
    void mapPoints (float[] dst, float[] src) 与上个方法作用一样,只不过是讲计算后的结果存放到dst数组中,src不变
    void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount) 作用和上边两个方法一致,只不过可以指定存储的数组长度。dstIndex表示目标数据存储位置起始下标,srcIndex表示原数据存储起始下标,pointCount表示计算的点个数
    float mapRadius (float radius) 测量半径,由于圆可能会因为画布变换变成椭圆,所以此处测量的是平均半径。radius表示原半径,返回的是经过变换之后的半径。
    boolean mapRect (RectF rect) 测量rect并将测量结果放入rect中,返回值是判断矩形经过变换后是否仍为矩形
    boolean mapRect (RectF dst, RectF src) 测量src并将测量结果放入dst中,返回值是判断矩形经过变换后是否仍为矩形
    mapVectors 和上边mapPoints方法类似,不过这里测量的是向量,也就是说平移操作不会影响结果

    set/pre/post控制平移(translate)、缩放(scale)、旋转(rotate)、 错切(skew) 的变换

    上边在讲Matrix原理的时候就已经对这些方法进行过讲解。

    特殊方法

    setPoluToPoly()

    boolean setPolyToPoly (
            float[] src,    // 原始数组 src [x,y],存储内容为一组点
            int srcIndex,   // 原始数组开始位置
            float[] dst,    // 目标数组 dst [x,y],存储内容为一组点
            int dstIndex,   // 目标数组开始位置
            int pointCount) // 测控点的数量 取值范围是: 0到4
    

    这个方法是控制两部分进行变换的。一是进行变换的点的数据,而是变化的点数。
    srcIndex定义要变换哪些点,中心点可以,四边形四边中点可以,四边形四个角可以,这里去的是容易获取的点;dstIndex表示根据srcIndex变换后的点;pointCount是变换点的数量;比如说你上边定义了四个点的变化,但是pointCount是1,那么结果可能就不是你想要得到的。

    pointCount 摘要
    0 相当于reset
    1 相当于translate
    2 可以进行 缩放、旋转、平移 变换
    3 可以进行 缩放、旋转、平移、错切 变换
    4 可以进行 缩放、旋转、平移、错切以及任何形变

    这个方法还是很有必要仔细研究的,具体代码我就不贴了,原博客中有详细讲解

    setRectToRect

    这个方法的作用主要就是填充的模式,比如一张图片要放到父空间中,图片尺寸比较小,那这张图片是要放在左上角,还是右下角,还是中间,还是铺满呢?setRectToRect方法就是控制这些操作的。

    boolean setRectToRect (RectF src,           // 源区域
                    RectF dst,                  // 目标区域
                    Matrix.ScaleToFit stf)      // 缩放适配模式
    
    模式 摘要
    CENTER 居中,对src等比例缩放,将其居中放置在dst中。
    START 顶部,对src等比例缩放,将其放置在dst的左上角。
    END 底部,对src等比例缩放,将其放置在dst的右下角。
    FILL 充满,拉伸src的宽和高,使其完全填充满dst。

    rectStaysRect

    判断举行变换之后是否还是矩形。

    invert

    获取矩阵的逆矩阵
    boolean invert (Matrix inverse)

    相关文章

      网友评论

        本文标题:自定义View(十)Matrix 基础理论与使用

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