这里咱们会详细讲解matrix的各个方法,以及它的用法。matrix叫作矩阵,在前面讲解 ColorFilter 的文章中,咱们讲解了ColorMatrix,他是一个4*5的矩阵。而这里,咱们讲解的Matrix不是用于处理颜色的,而是处理图形的。他是一个3*3的矩阵。html
先看看matrix的矩阵是什么样子的:canvas
这里能够查看Matrix的代码获得。那么这个矩阵分别表明了什么呢,这里经过他们的名字能够看出,scale是缩放,skew是错切(canvas变换中有讲过),trans是平移,persp表明透视(官方文档中,也没有详细讲解,透视在这里只作简单介绍)。这里须要把矩阵根据他们的做用划分为4块:api
如上图所示,这四块区域各有做用。后面会详细讲解各个做用,先来看看这个矩阵是如何影响图像的。先看看屏幕的坐标系:数组
看上图,这里表示了屏幕的坐标系,其中的x,y轴是你们所熟知的,可是其实,一个物体他是存在于一个三维空间的,因此必然会有z轴。咱们的屏幕,就像是一个窗口,透过它,咱们看到了屏幕后面的世界,那里面有各类物体,咱们看到的是映射在x,y平面上的一个投射图像。屏幕就像是一个镜头同样,将里面的物体映射到x,y平面上,成为一个二维的图像。那么若是,咱们把屏幕这个镜头沿着z轴,拉远或者拉进,那么图像会有什么变化呢,确定会变小或者变大。就比如坐在飞机上透过窗口看地面的汽车,和在地面上看到的大小是不一样的。app
结论就是,在屏幕上显示的像素,不只仅有x,y坐标,其实还有z轴的影响。因此这里对应的像素描述由一个3行一列的矩阵来表示:ide
x,y分别表明x,y轴上的坐标,而1表明屏幕在z轴上的坐标为默认的。若是将1变大,那么屏幕会拉远, 图形会变小。函数
如今咱们来看看matrix怎么做用于每一个像素的值。这里须要用到矩阵的乘法,首先须要明确的是,矩阵的前乘和后乘是不相同的,也就是说不知足乘法交换律。post
这里咱们经过一个旋转变换来看看原理,其实一张图片围绕一个点旋转,也就是全部的点都围绕一个点旋转,因此只须要关注一个点的状况便可:spa
假定有一个点 ,相对坐标原点顺时针旋转后的情形,同时假定P点离坐标原点的距离为r,以下图:.net
那么就有:
换作矩阵运算就以下图:
从这里就能够看出,矩阵中的值,是如何做用于像素点的x,y坐标以及z轴远近。
同时,能够看到,上面的矩阵四块区域的切分也是由于矩阵乘法的操做决定的,因为这里的乘法运算中,左上角的四个值,能够和x,y值作乘法运算,因此能够影响到旋转等操做,而右上角的模块,只能作加法,因此只能影响到平移。右下角的模块主要管z轴,天然就能够进行等比的缩放了,左下角的模块通常不去动他,不然会把x,y值加入到z轴中来,会不可控。
讲解完了matrix做用于像素点的原理以后,咱们逐个讲解它的方法。
public Matrix() public Matrix(Matrix src)
构造函数有两个,第一个是直接建立一个单位矩阵,第二个是根据提供的矩阵建立一个新的矩阵(采用deep copy)
单位矩阵以下:
public boolean isIdentity()//判断是不是单位矩阵 public boolean isAffine()//判断是不是仿射矩阵
是不是单位矩阵很简单,就不作讲解了,这里是不是仿射矩阵可能你们很差理解。
首先来看看什么是仿射变换。仿射变换其实就是二维坐标到二维坐标的线性变换,保持二维图形的“平直性”(即变换后直线仍是直线不会打弯,圆弧仍是圆弧)和“平行性”(指保持二维图形间的相对位置关系不变,平行线仍是平行线,而直线上点的位置顺序不变),能够经过一系列的原子变换的复合来实现,原子变换就包括:平移、缩放、翻转、旋转和错切。这里除了透视能够改变z轴之外,其余的变换基本都是上述的原子变换,因此,只要最后一行是0,0,1则是仿射矩阵。
public boolean rectStaysRect()
判断该矩阵是否能够将一个矩形依然变换为一个矩形。当矩阵是单位矩阵,或者只进行平移,缩放,以及旋转90度的倍数的时候,返回true。
public void reset()
重置矩阵为单位矩阵。
public void setTranslate(float dx, float dy)
设置平移效果,参数分别是x,y上的平移量。
效果图以下:
代码以下:
Matrix matrix = new Matrix(); canvas.drawBitmap(bitmap, matrix, paint); matrix.setTranslate(100, 1000); canvas.drawBitmap(bitmap, matrix, paint);
public void setScale(float sx, float sy, float px, float py) public void setScale(float sx, float sy)
两个方法都是设置缩放到matrix中,sx,sy表明了缩放的倍数,px,py表明缩放的中心。这里跟上面比较相似不作讲解了。
public void setRotate(float degrees, float px, float py) public void setRotate(float degrees)
和上面相似,再也不讲解。
public void setSinCos(float sinValue, float cosValue, float px, float py) public void setSinCos(float sinValue, float cosValue)
这个方法乍一看可能有点蒙,其实在前面的原理中,咱们讲解了一个旋转的例子,他最终的矩阵效果是这样的:
其实旋转,就是使用了这样的matrix,显而易见,这里的参数就清晰了。
sinValue:对应图中的sin值
cosValue:对应cos值
px:中心的x坐标
py:中心的y坐标
看一个示例,咱们把图像旋转90度,那么90度对应的sin和cos分别是1和0。
看代码以下:
Matrixmatrix = new Matrix(); matrix.setSinCos(1, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2); canvas.drawBitmap(bitmap, matrix, paint);
public void setSkew(float kx, float ky, float px, float py) public void setSkew(float kx, float ky)
错切,这里kx,ky分别表明了x,y上的错切因子,px,py表明了错切的中心。不了解错切了在前面canvas变换中去查看,这里再也不讲解。
public boolean setConcat(Matrix a,Matrix b)
将当前matrix的值变为a和b的乘积,它的意义在下面的 进阶方法中来探讨。
上面的基本方法中,有关于变换的set方法均可以带来不一样的效果,可是每一个set都会把上个效果清除掉,例如依次调用了setSkew,setTranslate,那么最终只有setTranslate会起做用,那么如何才和将两种效果复合呢。Matrix给咱们提供了不少方法。可是主要都是2类:
preXXXX:以pre开头,例如preTranslate
postXXXX:以post开头,例如postScale
他们分别表明了前乘,和后乘。看一段代码:
Matrix matrix = new Matrix(); matrix.setTranslate(100, 1000); matrix.preScale(0.5f, 0.5f);
这里matrix前乘了一个scale矩阵,换算成数学式以下:
从上面能够看出,最终得出的matrix既包含了缩放信息也有平移信息。
后乘天然就是matrix在后面,而缩放矩阵在前面,因为矩阵先后乘并不等价,也就致使了他们的效果不一样。咱们来看看后乘的结果:
能够看到,结果跟上面不一样,而且这也不是咱们想要的结果,这里缩放没有更改,可是平移被减半了,换句话说,平移的距离也被缩放了。因此须要注意先后乘法的关系。
来看看他们对应的效果图:
前乘:
后乘:
能够明显看到,后乘的平移距离受了影响。
了解清除了先后乘的意义,在使用的过程当中,多个效果的叠加时,同样要注意,不然效果达不到预期。
matrix除了上面的方法外,还有一些其余的方法,这里依次解析
public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf)
将rect变换成rect,上面的rectStaysRect已经说过,要保持rect只能作缩放平移和选择90度的倍数,那么这里其实也是同样,只是这几种变化,这里经过stf参数来控制。
ScaleToFit 有以下四个值:
FILL: 可能会变换矩形的长宽比,保证变换和目标矩阵长宽一致。
START:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。左上对齐。
CENTER: 保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。
END:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。右下对齐。
这里使用谷歌的api demo的图片做为例子:
public boolean setPolyToPoly(float[] src, int srcIndex,float[] dst, int dstIndex,int pointCount)
经过指定的0-4个点,原始坐标以及变化后的坐标,来获得一个变换矩阵。若是指定0个点则没有效果。
下面经过例子分别说明1到4个点的能够达到的效果:
这里写代码片
##### 1个点,平移
只指定一个点,能够达到平移效果:
代码以下:
float[] src = {0, 0}; int DX = 300; float[] dst = {0 + DX, 0 + DX}; matrix.setPolyToPoly(src, 0, dst, 0, 1); canvas.drawBitmap(bitmap, matrix, paint);
两个点,能够达到旋转效果或者缩放效果,缩放比较简单,这里咱们来看旋转效果,一个点指定中心,一点指出旋转的效果
代码以下
int bw = bitmap.getWidth(); int bh = bitmap.getHeight(); float[] src = {bw / 2, bh / 2, bw, 0}; float[] dst = {bw / 2, bh / 2, bw / 2 + bh / 2, bh / 2 + bw / 2}; matrix.setPolyToPoly(src, 0, dst, 0, 2); canvas.drawBitmap(bitmap, matrix, paint);
图片的中心点做为旋转的中心,先后不变,右上角变化到了下方,因此致使图片旋转了90度。
使用3个点,能够产生错切效果,指定3个顶点,一个固定,另外两个移动。
看图:
代码以下:
Matrix matrix = new Matrix(); int bw = bitmap.getWidth(); int bh = bitmap.getHeight(); float[] src = {0,0, 0, bh,bw,bh}; float[] dst = {0, 0, 200, bh, bw + 200, bh}; matrix.setPolyToPoly(src, 0, dst, 0, 3); canvas.drawBitmap(bitmap, matrix, paint);
透视就是观察的角度变化了。致使投射到平面上的二维图像变化了。
咱们看下面的例子,更容易理解:
图片看起来好像倾斜了,实现特别简单:
Matrix matrix = new Matrix(); int bw = bitmap.getWidth(); int bh = bitmap.getHeight(); float[] src = {0, 0, 0, bh, bw, bh, bw, 0}; int DX = 100; float[] dst = {0 + DX, 0, 0, bh, bw, bh, bw - DX, 0}; matrix.setPolyToPoly(src, 0, dst, 0, 4); canvas.drawBitmap(bitmap, matrix, paint);
能够看到,只是把左右两个顶点往里面收拢了,这样就得出了一个有3d效果的透视图。
public boolean invert(Matrix inverse)
反转当前矩阵,若是能反转就返回true并将反转后的值写入inverse,不然返回false。当前矩阵*inverse=单位矩阵。
反转先后有什么效果,咱们来看看示例:
能够看到,反转以后,实际上是对效果的一种反转。
public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,int pointCount) public void mapPoints(float[] dst, float[] src) public void mapPoints(float[] pts)
映射点的值到指定的数组中,这个方法能够在矩阵变换之后,给出指定点的值。
dst:指定写入的数组
dstIndex:写入的起始索引,x,y两个坐标算做一对,索引的单位是对,也就是通过两个值才加1
src:指定要计算的点
srcIndex:要计算的点的索引
pointCount:须要计算的点的个数,每一个点有两个值,x和y。
public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,int vectorCount) public void mapVectors(float[] dst, float[] src) public void mapVectors(float[] vecs)
与上面的mapPoionts基本相似,这里是将一个矩阵做用于一个向量,因为向量的平移先后是相等的,因此这个方法不会对translate相关的方法产生反应,若是只是调用了translate相关的方法,那么获得的值和本来的一致。
public boolean mapRect(RectF dst, RectF src) public boolean mapRect(RectF rect)
返回值便是调用的rectStaysRect(),这个方法前面有讲过,这里把src中指定的矩形的左上角和右下角的两个点的坐标,写入dst中。
public float mapRadius(float radius)
返回一个圆圈半径的平均值,将matrix做用于一个指定radius半径的圆,随后返回的平均半径。
以上基本解析完毕了全部matrix的方法,以及一些高阶用法,本篇文章就到这里