在二维平面上,常用的有以下三种基本的图形变化:
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矩阵,大家明白没有?
关于矩阵左乘右乘,前乘后乘的关系,如果有困惑的朋友,可以看一下下面这篇文章:
分享到:
相关推荐
图形学2D图形变换程序,可以完成对称等各种变换
实验六: 2D图形的变换
本论文用于计算机图形学基于2D的图形变换,如果不能实现敬请原谅,谢谢。
该类封装了平面坐标的矩阵运算的方法,包括正算、反算以及旋转参数、平移参数、错切变换、比例绽放参数的设置,请详见代码中的注释
基于OpenCV的二维矩阵刚性变换(旋转,平移),已知两点集,求解R&T变换矩阵,其中自定义接口,已经赋初值,可以更改调用
2d平面在3d中展示,使用threejs,使得2d渲染的平面div在3d世界上真实展示,并且真实显示和响应按钮事件。
WebGL-2D-矩阵
2d walsh变换,包含变换和反转,转换2D矩阵或图像,然后用户可以使用相同的反函数返回2D矩阵
c语言实现的2*3的矩阵变换(验证过的),没有问题
2D坐标系中的矩阵变换,坐标位置根据某一点做旋转,平移,得到新的坐标位置。附件中的实例下载运行后可以直接看到效果
二维图形变换。2D变换示例。可以实现大多数2D变换(TC2.0下通过)
一幅二维数字图像可以用矩阵[g(m,n)]来表示,g(m,n)是图像在坐标(m,n)处的灰度级(或彩色RGB值)。也可以把g(m,n)视为一个二元函数,它的自变量为m和n,则可以用它来表示数字...定义1:二维矩阵向量[g(m,n)]的2D-DFT
学习Matrix的对图像的处理可分为四类基本变换: Translate平移变换 Rotate 旋转变换 Scale缩放变换 Skew 错切变换 最好的demo
计算机图形学实验(作业利器) 主题:2D变换演示程序 code in python 2.7.15, author:zhu 看官先行品鉴,如有源码需要站内私信。
Matrix2D.js 二维矩阵文档()如何使用浏览器 < script src = "lib/Matrix2D.js" >< script >console.log( Matrix2D.identity() );< / script >网络工作者 importScripts ( "lib/Matrix2D.js" ) ;...
内涵3节课程的游戏Demo,层层深入,用的图形库是我自己封装的Direct2D为基础的库,游戏实现了人物动画,坐标转换,Z-Buffer,想学习游戏制作的朋友可以参考。
用Java2D实现的图形沿某一直线的伸缩变换
矩阵可以选择同步画布 2D 上下文对象,以便画布上的变换与像素完美匹配 Matrix 对象的局部变换。 使用 toCSS() 也可以同步一个 DOM 元素。 没有依赖性。 现在还包括一个矢量反射方法(参见包含的演示示例用法)...
将多个变换矩阵合并到一个由多个矩阵组成的矩阵中 双向使用字符串: parse , render 将转换矩阵应用于点 使用示例(ES6) import { scale , rotate , translate , compose , applyToPoint } from 'transformation...
draw2d 绘制图形教程 draw2d 绘制图形教程draw2d 绘制图形教程 draw2d 绘制图形教程