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

1)Translation

2)Scale

3)Rotation

在canvas的开发中,我们也经常会用到这样的一些图形变换,尤其是我们在写自定义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',我们只要加上这个偏移就行,如果用矩阵或者向量来表示就是:
(可能会有朋友觉得奇怪,怎么是加呢,canvas里面矩阵不都是乘吗?这是什么原因呢?)

Scale(缩放)

那如果我们对这条直线进行放大呢,比如放大2倍呢,一般来讲,我们缩放,是指所有维度的缩放,当然在这里就只有x坐标跟y坐标,当然也可以只针对一个维度,但是就会变形了哦。我们先看一下放大到2倍的效果和只放大列的效果吧。
          
很显然,两边都放大的话,起始点由(120,0)变成(240,0),终点由(240,120)变成(480,240)。而如果只放大列的话,起始点的坐标是不变的。而且我们可以看到,放大的时候,线也跟着向右平移了一个单位,为什么会这样呢?这是因为缩放是基于原点(0,0)的,在canvas中,也就是屏幕的左上角,但缩放的位数大于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(旋转)相对应的矩阵也就变成:
看到这几个,大家发现了没有?没错,这几个就是我们canvas中用到的矩阵了。
 
当我们在Canvas上用Scale的时候,其实就是乘上S矩阵,当我们用Rotate的时候,其实就是乘上R矩阵,大家明白没有?
转载自:https://blog.csdn.net/linmiansheng/article/details/18801947
关于矩阵左乘右乘,前乘后乘的关系,如果有困惑的朋友,可以看一下下面这篇文章:
https://blog.csdn.net/linmiansheng/article/details/18820599
 
另外矩阵相关文章:
https://www.cnblogs.com/fangsmile/p/5651429.html
 
 

2D平面中关于矩阵(Matrix)跟图形变换的讲解的更多相关文章

  1. 自定义View(11)**在onDraw中使用矩阵Matrix

    1.代码示例 1.1 效果 原图 : 其尺寸为162 x 251,示例中的红点是变形的锚点. 变形之后: 1.2 代码 package com.e.weixin.session.view; impor ...

  2. WebGL简易教程(五):图形变换(模型、视图、投影变换)

    [toc] 1. 概述 通过之前的教程,对WebGL中可编程渲染管线的流程有了一定的认识.但是只有前面的知识还不足以绘制真正的三维场景,可以发现之前我们绘制的点.三角形的坐标都是[-1,1]之间,Z值 ...

  3. 机器学习中的矩阵方法04:SVD 分解

    前面我们讲了 QR 分解有一些优良的特性,但是 QR 分解仅仅是对矩阵的行进行操作(左乘一个酉矩阵),可以得到列空间.这一小节的 SVD 分解则是将行与列同等看待,既左乘酉矩阵,又右乘酉矩阵,可以得出 ...

  4. CSS3中的矩阵

    CSS3中的矩阵 CSS3中的矩阵指的是一个方法,书写为matrix()和matrix3d(),前者是元素2D平面的移动变换(transform),后者则是3D变换.2D变换矩阵为3*3,如下面矩阵示 ...

  5. Three.js-任意平面的镜像矩阵

    1. 什么是镜像变换 直接看下面这张图: 这张图很好的诠释了镜像变化,关于y轴的变化,关于x轴的变化.这种关于任意轴的变化,就是镜像了. 2d下的镜像矩阵变化 我们以图像关于Y轴镜像为例子:原图形和结 ...

  6. 变形--矩阵 matrix()

    matrix() 是一个含六个值的(a,b,c,d,e,f)变换矩阵,用来指定一个2D变换,相当于直接应用一个[a b c d e f]变换矩阵.就是基于水平方向(X轴)和垂直方向(Y轴)重新定位元素 ...

  7. 关于opengl中的矩阵平移,矩阵旋转,推导过程理解 OpenGL计算机图形学的一些必要矩阵运算知识

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12166896.html 为什么引入齐次坐标的变换矩阵可以表示平移呢? - Yu Mao的回答 ...

  8. MATLAB中求矩阵非零元的坐标

    MATLAB中求矩阵非零元的坐标: 方法1: index=find(a); [i,j]=ind2sub(size(a),index); disp([i,j]) 方法2: [i,j]=find(a> ...

  9. numpy教程:矩阵matrix及其运算

    http://blog.csdn.net/pipisorry/article/details/48791403 numpy矩阵简介 NumPy函数库中存在两种不同的数据类型(矩阵matrix和数组ar ...

随机推荐

  1. js的事件机制二

    js的事件机制二 1.给合适的HTML标签添加合适的事件 onchange-----select下拉框 onload-----body标签 单双击-----用户会进行点击动作的HTML元素 鼠标事件 ...

  2. python学习笔记1.4

    注释不被程序执行的辅助性说明信息- 单行注释:以#开头,其后内容为注释# 这里是单行注释- 多行注释:以'''开头和结尾''' 这是多行注释第一行这是多行注释第二行 ''' 保留字and elif i ...

  3. C#-WinForm-★★★★★跨窗体 构造函数传值 及应用—登录式窗口传值、如何关闭主页面时关闭应用程序、如何打开唯一窗口★★★★★

    构造函数可以传任意类型的值,并可以同时传多个值 结构函数传值的初步应用——简单的登陆式界面 现在我有两个窗体Form3和Form4,如下,如何点击Form3中的按钮后,打开Form4并将Form3中的 ...

  4. 2D激光SLAM算法比较+cartographer

    Hector slam: Hector slam利用高斯牛顿方法解决scan-matching问题,对传感器要求较高. 缺点:需要雷达(LRS)的更新频率较高,测量噪声小.所以在制图过程中,需要rob ...

  5. Unity 行为树-中断机制

    一.中断类型 设置了中断之后,行为树会检测执行过的子条件节点,当条件节点的状态发生变化时,会中断正在执行的Running节点,转而立即执行该条件节点. 行为树的打断类型有4种: None Self L ...

  6. JavaWeb学习笔记(十九)—— 分页

    一.MySQL中的分页 格式:select * from 表 limit ?,?; 参数1:开始索引start,默认值:.必须是正数 参数2:每页显示个数 pageSize 例如: ,; #第一页,每 ...

  7. AMPQ 0-9-1学习笔记

    AMQP 0-9-1学习笔记 AMQP(Advanced Message Queuing Protocol)高级消息队列协议:是一个进程间传递异步消息的网络协议 2. AMQP的基本模型: Publi ...

  8. Java生成树关系的菜单

    1.菜单bean public class Menu { private String id; private String menuname; private String parentid; pr ...

  9. CSAPP阅读笔记-汇编语言初探(算术和逻辑操作类指令)-来自第三章3.5的笔记-P128-P135

    1.算术和逻辑操作类指令分四类:加载有效地址,一元操作,二元操作和移位,如下: 2. leaq指令,类似mov指令,它左侧的数看似是给出一个地址,在内存中从给定的地址取操作数,传给右边的目的地.但其实 ...

  10. MySQL 的更新操作update

    1 更新操作(单表更新) 1)单表更新 update [low_priority] [ignore] table_reference set col_name1={expr1|default},col ...