• 2D平面中关于矩阵(Matrix)跟图形变换的讲解


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

    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的代码中看到的,如下:
     1     /**
     2      * Preconcat the current matrix with the specified scale.
     3      *
     4      * @param sx The amount to scale in X
     5      * @param sy The amount to scale in Y
     6      * @param px The x-coord for the pivot point (unchanged by the scale)
     7      * @param py The y-coord for the pivot point (unchanged by the scale)
     8      */
     9     public final void scale(float sx, float sy, float px, float py) {
    10         translate(px, py);
    11         scale(sx, sy);
    12         translate(-px, -py);
    13     }
    上面代码中的轴点的实现,其实就是对于平移的来回操作,至于为什么是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
     
     
  • 相关阅读:
    in_array函数的第三个参数 strict
    主动创建缓存与被动创建缓存
    INSERT IGNORE 与INSERT INTO的区别
    说说php取余运算(%)的那点事
    继承中的类常量的使用
    Scribe 分布式日志收集系统
    PHP命令行模式基本介绍
    【C/C++】学生排队吃饭问题
    【C/C++】链表
    【C/C++】01背包问题/动态规划
  • 原文地址:https://www.cnblogs.com/fangsmile/p/9324194.html
Copyright © 2020-2023  润新知