在二维平面上,常用的有以下三种基本的图形变化:

1)Translation

2)Scale

3)Rotation

在Android的开发中,我们也经常会用到这样的一些图形变换,尤其是我们在写自定义View时,更是会经常利用到Matrix来实现一些效果,比如平移,旋转,缩放及切变等,相信很多朋友应该很想知道,矩阵实现这种变换的原理是什么,什么是矩阵的左乘右乘,它们在实现效果上有什么差别吗?今天就让我们一起来看一下吧。

都是由点组成的

平面上的元素,就是点,线,面,而线就是由一个个点组成的,而是由一条条线组成的,所以归根结底,平面上所有的图形都是由点组成的。而在我们坐标系中,一个点就是由一对x,y值组成的,p = {x, y}。而在平面上,过两点间的,我们可以画一条直线,所以我们一般通过 p1, p2可定义一条直线,e = {p1, p2},而图形呢,则是由众多的点和点之间的的线段组成的。所以,其实平面上的图形变换,就是点坐标位置的变换。 在平面上,一个点,可以通过一个向量或者矩阵来表示:
而下面这条红色的直线则是由一组组的点组成的,起始点是(120,0),终点是(240,120)。

Translation(平移)

如果我们现在要平移这条直线,向右120(tx),向下120(ty),那么新的点会是怎么样呢?很显然,起始点就会是(240,120),而终点就会是(360,240),效果如下:
绿色的线就是平移后的线了,可以看出每一个新的点的值是
这样的一个变换translation也可以用一对值来表示,t = {tx, ty},其中tx是在x坐标上的偏移量,而ty是在y坐标上的偏移量。移动点 p 到 p',我们只要加上这个偏移就行,如果用矩阵或者向量来表示就是:
(可能会有朋友觉得奇怪,怎么是加呢,Android里面矩阵不都是乘吗?这是什么原因呢?)

Scale(缩放)

那如果我们对这条直线进行放大呢,比如放大2倍呢,一般来讲,我们缩放,是指所有维度的缩放,当然在这里就只有x坐标跟y坐标,当然也可以只针对一个维度,但是就会变形了哦。我们先看一下放大到2倍的效果和只放大列的效果吧。           
很显然,两边都放大的话,起始点由(120,0)变成(240,0),终点由(240,120)变成(480,240)。而如果只放大列的话,起始点的坐标是不变的。而且我们可以看到,放大的时候,线也跟着向右平移了一个单位,为什么会这样呢?这是因为缩放是基于原点(0,0)的,在Android中,也就是屏幕的左上角,但缩放的位数大于1的时候,就会远离原点,而相反,当缩放的位数小于1时,则会趋近原点。 缩放的变换是由下面的矩阵来表示的:
那么缩放后的直线的点就是:
各位朋友,可以想一下,这样直接Scale的话,这个图形可是会平移的哦,如果不想要平移,应该怎么办?

Rotation(旋转)

我们再看一下下图,这条直线顺时针旋转了45度,也就是往逆时针方向旋转了 - 45 度,

那么新的点是怎么算出来的呢? 逆时针(注意这里)旋转的矩阵表示是:
同样的,旋转后的点就是根据下面的矩阵相乘而得出来的结果:
我们可以将我们的点代进去求解,可得新的起始点P0'为(84.85,84.85),而新的结束点为:(84.85,254.56),可看出,刚好是上面绿色线所在的地方。

Combine Transformation (组合变换)

对于Scale 和 Rotation 来说,它们都是基于原点(0,0)的变换,那如果我们要让它基于某个点缩放或者旋转,就比如绕着起始点转呢,而这也经常是我们想要的一种效果。这个点就是所谓的旋转,而解决办法其实就是将图形先平移到原点,再进行缩放或者旋转的变化,然后再移回来,就可以了。 假设这三种变换的矩阵表示如下:

那么它应该实施的变换就如下:先平移 T 到原点,再基于原点进行缩放(或者旋转),然后再平移回去,

其实这一步,我们可以在Canvas的代码中看到的,如下:
    /**     * Preconcat the current matrix with the specified scale.     *     * @param sx The amount to scale in X     * @param sy The amount to scale in Y     * @param px The x-coord for the pivot point (unchanged by the scale)     * @param py The y-coord for the pivot point (unchanged by the scale)     */    public final void scale(float sx, float sy, float px, float py) {        translate(px, py);        scale(sx, sy);        translate(-px, -py);    }
上面代码中的轴点的实现,其实就是对于平移的来回操作,至于为什么是translate(px,py)在前,而translate(-px,py)在后呢,这涉及到矩阵左乘和右乘的计算,后面我们会谈到的。

Homogeneous Coordinates(齐次坐标)

在上面的矩阵中,我们可以看到平移的矩阵是相加的,而旋转跟缩放的矩阵都是相乘的,这样计算起来多麻烦呀!于是为了方便计算,大家都统一用一种方式来进行计算,聪明的计算机图形科学家,它们就设计出这样一种坐标系,叫homogeneous coordinates,而它的目的只是为了更加方便地去用矩阵来计算图形的变换,没有其他。 那什么是齐次坐标呢? 其实就是在原来2D的维度,再加上一个新的维度,多出来的维度的值永远是1,比如点的矩阵就变成:
而Translation(平移)的矩阵表示就变成:
这样,平移变换的加法就可以变成乘法:
而Scale(缩放)跟Rotation(旋转)相对应的矩阵也就变成:
看到这几个,大家发现了没有?没错,这几个就是我们Android中用到的矩阵了。
当我们在Canvas上用Scale的时候,其实就是乘上S矩阵,当我们用Rotate的时候,其实就是乘上R矩阵,大家明白没有? 关于矩阵左乘右乘,前乘后乘的关系,如果有困惑的朋友,可以看一下下面这篇文章:  

Android中关于矩阵(Matrix)前乘后乘的一些认识



更多相关文章

  1. Android(安卓)图片拖拽、放大缩小的自定义控件
  2. Android绘图机制与处理技巧——Android图像处理之色彩特效处理
  3. Android(安卓)应用的动画实践--View Animation篇
  4. Android中图片压缩方案详解及源码下载
  5. 图像处理-矩阵变换
  6. [翻译]Android单手指缩放-第一部分(Android(安卓)one finger zoom
  7. Android简易实战教程--第二十八话《加载大图片》
  8. Android(安卓)ColorMatrix 亮度矩阵 对比度矩阵 黑白矩阵
  9. Android中的网络应用之网页设置,检测、配置用户设备属性。

随机推荐

  1. Android SDK 快速安装方法
  2. android获取APK签名信息及MD5指纹
  3. 【面包屑】快速使用RecyclerView搭建列表
  4. 修改ListView的分割线
  5. Android之Handler详解(四)
  6. Android LayoutInflater
  7. eclipse导入的Android项目没有android.ja
  8. Android面试系列文章2018之Android部分Ha
  9. Android SearchView 搜索框
  10. Android打印相关