Android笔记 自定义View(九):Matrix介绍

目录

前言

一、Matrix简介

二、Matrix的四种变换

         2.1、 Translate(平移)

2.2、 scale(缩放)

2.3、 skew(错切)

2.4、 旋转变换

2.5、总结

三、setXXX、preXXX、postXXX

总结


前言

在 Android 开发中,矩阵是一个功能强大并且应用广泛的神器,例如:用它来制作动画效果、改变图片大小、给图片加各类滤镜等。对于矩阵,Android 官方 SDK 为我们提供了一个强大的类 Matrix (还有 ColorMatrix )。由于在开发中接触矩阵的相关内容的机会较少,对其了解的也就很贫乏。现在有时间就记录下自己的理解

一、Matrix简介

Matrix中文是矩阵的意思。Matrix是Android SDK提供的一个矩阵类。官方文档对Matrix类的说明:

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

大概意思是:Matrix类包含一个3x3矩阵,用于转换坐标。 Matrix类提供了让我们获得矩阵值的方法:toShortString()。代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Matrix matrix=new Matrix();
        Log.i("TAG","matrix:"+matrix.toShortString());
    }

日志结果:

可以看出Matrix初始值是一个单位矩阵。Matrix为这个数组中的每一个元素都定义了一个下标常量:

    public static final int MSCALE_X = 0;   //!< use with getValues/setValues
    public static final int MSKEW_X  = 1;   //!< use with getValues/setValues
    public static final int MTRANS_X = 2;   //!< use with getValues/setValues
    public static final int MSKEW_Y  = 3;   //!< use with getValues/setValues
    public static final int MSCALE_Y = 4;   //!< use with getValues/setValues
    public static final int MTRANS_Y = 5;   //!< use with getValues/setValues
    public static final int MPERSP_0 = 6;   //!< use with getValues/setValues
    public static final int MPERSP_1 = 7;   //!< use with getValues/setValues
    public static final int MPERSP_2 = 8;   //!< use with getValues/setValues

按照上面输出日志的结果和下标的对应关系,将它排列成矩阵的格式,如下:

Matrix 就是通过改变对应的矩阵元素的值来进行 Translate(平移)、Scale(缩放)、Rotate(旋转)、Skew(错切)操作的,。变换操作与矩阵中元素的对应关系如下:

Translate          

平移变换MTRANS_X, MTRANS_Y
Rotate  旋转变换MSCALE_X, MSCALE_Y , MSKEW_X , MSKEW_Y
Scale  缩放变换MSCALE_X, MSCALE_Y
Skew 错切变换MSKEW_X, MSKEW_Y

从表中可以看出:只有最后一行的三个参数没有涉及到。其实它们是固定值,分别为0,0,1。为什么要这样?往下看。

二、Matrix的四种变换

 Matrix提供了translate(平移)、scale(缩放)、rotate(旋转)、skew(错切)四种操作。由于所有的图形都是有像素点组成,因此我们只需要考察一个点相关变换即可。

ps:除平移变换(Translate)外,旋转变换(Rotate)、缩放变换(Scale)和错切变换(Skew)都可以围绕一个中心点来进行,如果不指定,在默认情况下是围绕(0, 0)来进行相应的变换的。

2.1、 Translate(平移)

将点 其移动到 ,如下图所示:

。则:

用矩阵表示为:

2.2、 scale(缩放)

理论上而言,对于一个像素点来说,不存在缩放的概念,但一个图像是由很多个像素点组成,将每个点的坐标进行相同比例的缩放后,整个图像也就有了缩放的效果。

矩阵表示为:

ps:k是要缩放的比例:负值无效,会不显示;0<k<1缩小;k>1放大

2.3、 skew(错切)

错切是一种比较特殊的线性变换,分为水平错切和垂直错切。错切变换的效果就是让所有点的x坐标(或者y坐标)保持不变,而对应的y坐标(或者x坐标)则按比例发生平移,且平移的大小和该点到x轴(或y轴)的垂直距离成正比。错切变换,属于等面积变换,即一个形状在错切变换的前后,其面积是相等的。

比如下图,各点的y坐标保持不变,但其x坐标则按比例发生了平移。这种情况将水平错切。

下图各点的x坐标保持不变,但其y坐标则按比例发生了平移。这种情况叫垂直错切。

假定一个点经过错切变换后得到,对于水平错切而言,应该有如下关系:

同理垂直错切:

复合错切:

矩阵表示为:

2.4、 旋转变换

假定有一个点 ,相对坐标原点顺时针旋转后的情形,同时假定P点离坐标原点的距离为r,如下图:

那么,

同样,用换成矩阵表示为:

2.5、小结

以上四种变换,矩阵形形式表示如下:

可以看出其实使用2x2的矩阵就可以完成四种变换了,那为什么Matix是3x3的矩阵呢?

从上面的矩阵表达式可以看出,平移是矩阵相加,旋转、缩放和错切则是矩阵相乘。能不能都用乘法来计算?,数学大神们为了统一算法引入了一样神器齐次坐标(自行百度),将平移的加法合并用乘法表示。所以,2 X 2 的矩阵经过一番变换后,如下。

所以,其实 2 X 2 的矩阵是足以表示的,不过是为了统一算法方便计算而合并写成了 3 X 3 的格式。这也就解释了为什么最后一行的三个值是固定的0,0,1。

三、setXXX、preXXX、postXXX

以上四种变换,针对每一种变换Matrix均提供pre,post和set三类操作。例如位移变换:setTranslate,preTranslate,postTranslate:官方文档对于preTranslate的说明,如下:

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

pre相当于矩阵的右乘。也叫后乘

postTranslate

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

post相当于矩阵的左乘。也叫前乘

setTranslate

Set the matrix to translate by (dx, dy).

直接设置矩阵的值覆盖之前的操作,会导致之前的操作失效。

在数学中矩阵乘法有几条规律:

  • 任何矩阵与单位矩阵相乘都等于本身:M·A=A·M=A
  • 不满足交换律:A·B≠B·A;
  • 乘法结合律:(A·B)·C=A·(B·C);

在Matrix初始化后得到就是单位矩阵,即

我们将四种变换假定为T(平移)、Sc(缩放)、R(旋转)、Sk(错切)。由于setXXX很好理解这里不做说明。现在有一组变换

Matrix matrix = new Matrix();
matrix.preTranslate(100f, 100f);
matrix.postScale(0.5f, 0.5f);
matrix.preSkew(0.5f,0.5f);
matrix.postRotate(90);
matrix.postTranslate(-100f, -100f);

用矩阵表示就是:M′=T·R·Sc·M·T·Sk,带入坐标:

 

小结:

  1. 根据上述第一条规律,当只存在一种变换时,preXXX和post没有区别:Sc·M=M·Sc=Sc,(注意:M为单位矩阵)。此时上面的复合变换公式为:M′=T·R·Sc·T·Sk。
  2. 根据上述第二条规律,复合变换时preXXX和postXXX结果不同。
  3. 根据上述第三条规律,为了理解方便,从运算规则的角度可以改变计算顺序:

            此时可以将整个复合变换看成是一个变换队列:postXXX就是往队列前排插入变换顺序靠后;preXXX是往队列后排插入变换顺序靠前。但是实际的代码执行顺序是不会变的。

ps:以上的小结只是个人理解,如果有错误的地方,后面会再修正。

总结

Matrix类中还存在很多其他的方法,可以列出一个方法表,如下:

方法类别相关API摘要
基本方法equals hashCode toString toShortString比较、 获取哈希值、 转换为字符串
数值操作set reset setValues getValues设置、 重置、 设置数值、 获取数值
数值计算mapPoints mapRadius mapRect mapVectors计算变换后的数值
设置(set)setConcat setRotate setScale setSkew setTranslate设置变换
前乘(pre)preConcat preRotate preScale preSkew preTranslate前乘变换
后乘(post)postConcat postRotate postScale postSkew postTranslate后乘变换
特殊方法setPolyToPoly setRectToRect rectStaysRect setSinCos一些特殊操作
矩阵相关invert isAffine isIdentity求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 …

这篇文章中,作者已经有了详细的解释有兴趣的小伙伴们可以自己研究下。由于Google已经对与Matrix已经做了很好的封装,所以跳过这部分对实际开发影响并不会太大。但是对于Matrix的理解会使我们对自定view会更加的得心应手。

祝:工作顺利!

 

参考资料

https://www.jianshu.com/p/6aa6080373ab

http://www.gcssloop.com/customview/CustomViewIndex/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值