AffineTransform -> 仿射变换

作者: 寻形觅影 | 来源:发表于2017-06-29 16:28 被阅读452次

    CoreGraphics框架中的CGAffineTransform类可用于设定UIView及其子类的transform属性,控制视图的缩放、旋转和平移等操作。
    在此主要介绍一下仿射变换及CGAffineTransform类的用法。

    1、定义:

    AffineTransform类描述了一种仿射变换的功能,它是一种二维坐标到二维坐标之间的线性变换,保持二维图形的“平直性”(即变换后直线还是直线不会打弯,圆弧还是圆弧。)和“平行性”(即保持二维图形间的相对位置关系不变,平行线还是平行线,而直线上点的位置顺序不变,另特别注意向量间夹角可能会发生变化。)
    常用的仿射变换:平移(Translation)、旋转(Rotation)、缩放(Scale)。

    2、原理:

    一个任意的仿射变换都能表示为 乘以一个2 x 2矩阵 (线性变换) 再加上一个向量 (平移)。 即经历一个3x3的矩阵的变换(这样说好像很难理解,下面我们通过代码定义举例来说明)

    3、解读:

    (1.) CGAffineTransform官方定义:

    struct CGAffineTransform {
      CGFloat a, b, c, d; // 这四个参数主要管理线性变换
      CGFloat tx, ty; // 这两个主要管理平移
    };
    

    该结构体中只有a,b,c,d,tx,ty 6个参数,但其实还有3个固定的参数[0,0,1]来组成3x3的矩阵:

    a表示x水平方向的缩放,tx表示x水平方向的偏移
    d表示y垂直方向的缩放,ty表示y垂直方向的偏移
    如果b和c不为零的话,那么视图肯定发生了旋转

    e.g : 一个点 CGPoint(x , y) 经过该仿射变换后变成另外一个点 * CGPoint(x1 , y1)* 可以表示为:

    [x1 y1 1] = [ x y 1] *


    即:

    x1 = ax + cy + tx;
    y1 = bx + dy + ty;

    (2.) 常用方法与定义:
    1、

    /* The identity transform: [ 1 0 0 1 0 0 ]. 
       这是默认的值,是单位矩阵;所有View及其子类默认的 transform均为 CGAffineTransformIdentity;
       所有向量与单位向量相乘均为本身;
    */
    CG_EXTERN const CGAffineTransform CGAffineTransformIdentity;
    
    /* Return the transform [ a b c d tx ty ]. 
       返回一个自定义的仿射变换(对矩阵变换有信心的可以根据需求自由定义来实现效果~)
    */
    CG_EXTERN CGAffineTransform CGAffineTransformMake(CGFloat a, CGFloat b,
      CGFloat c, CGFloat d, CGFloat tx, CGFloat ty);
    
    /* Return a transform which translates by `(tx, ty)':
         t' = [ 1 0 0 1 tx ty ] 
       通过tx ty 返回一个平移的变换矩阵
       tx为正数右移,负值左移;ty正数下移,负值上移;
    */
    CG_EXTERN CGAffineTransform CGAffineTransformMakeTranslation(CGFloat tx,
      CGFloat ty) ;
    
    /* Return a transform which scales by `(sx, sy)':
         t' = [ sx 0 0 sy 0 0 ] 
       通过 sx sy 返回一个缩放的变换矩阵(sx  sy 即 a  c  其他的b和d 为0)
    */
    CG_EXTERN CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy);
    
    /* Return a transform which rotates by `angle' radians:
       t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] 
       通过 angle返回一个旋转的变换矩阵;
       angle 为弧度:系统自带常用弧度有:M_E、M_LOG2E、M_LOG10E、M_LN2、M_LN10、M_PI、M_PI_2、M_PI_4、M_1_PI、M_2_PI。
       分别对应:e、log2(e)、log10(e)、loge(2)即ln(2)、loge(10)即ln(10)、π、π/2、π/4、1/π、2/π。
       正数为顺时针旋转,负数为逆时针旋转。
    */
    CG_EXTERN CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle);
    
    /* Return true if `t' is the identity transform, false otherwise. 
       判断一个矩阵变换是否是单位矩阵,是返回yes,否则返回no
    */
    CG_EXTERN bool CGAffineTransformIsIdentity(CGAffineTransform t);
    

    *以上的矩阵变换均是针对默认单位矩阵做出的变换!!!
    例如:先将一个视图旋转45°,然后将其宽高缩小为原来的二分之一则与直接将其缩小得到的结果是一样的!!!

    示例代码-1 效果展示-2

    2、

    /* Translate `t' by `(tx, ty)' and return the result:
         t' = [ 1 0 0 1 tx ty ] * t
        在某一个矩阵变换t的基础上进行平移变换
     */
    CG_EXTERN CGAffineTransform CGAffineTransformTranslate(CGAffineTransform t,
      CGFloat tx, CGFloat ty);
    
    /* Scale `t' by `(sx, sy)' and return the result:
         t' = [ sx 0 0 sy 0 0 ] * t 
        在某一个矩阵变换t的基础上进行缩放变换
    */
    CG_EXTERN CGAffineTransform CGAffineTransformScale(CGAffineTransform t,
      CGFloat sx, CGFloat sy);
    
    /* Rotate `t' by `angle' radians and return the result:
         t' =  [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t 
        在某一个矩阵变换t的基础上进行旋转变换
    */
    CG_EXTERN CGAffineTransform CGAffineTransformRotate(CGAffineTransform t,
      CGFloat angle);
    
    /* Invert `t' and return the result. If `t' has zero determinant, then `t' is returned unchanged. 
       根据变换矩阵t 生成一个与之效果相反的变换矩阵
    */
    CG_EXTERN CGAffineTransform CGAffineTransformInvert(CGAffineTransform t);
    
    /* Concatenate `t2' to `t1' and return the result:
         t' = t1 * t2
        结合两个矩阵变换t1、t2 新的矩阵为矩阵t1与矩阵t2的乘积:t1*t2(不能写反,t1*t2 与t2*t1的结果不一定相同)
     */
    CG_EXTERN CGAffineTransform CGAffineTransformConcat(CGAffineTransform t1,
      CGAffineTransform t2);
    
    /* Return true if `t1' and `t2' are equal, false otherwise. 
        判断连个变换矩阵是否相同
    */
    CG_EXTERN bool CGAffineTransformEqualToTransform(CGAffineTransform t1,
    CGAffineTransform t2);
    

    以上涉及矩阵变换的矩阵可以将多重效果组合使用!

    示例代码-2 效果展示-2

    从代码可以看到,红色视图是先创建了缩放变换然后在此基础上添加了旋转变换;蓝色视图是直接通过函数调用将两种变换结合到一起,但是效果是一样的。

    /* Transform `point' by `t' and return the result:
         p' = p * t
       where p = [ x y 1 ].
       获取经过矩阵变换后的点;
     */
    CG_EXTERN CGPoint CGPointApplyAffineTransform(CGPoint point,
      CGAffineTransform t);
    
    /* Transform `size' by `t' and return the result:
         s' = s * t
       where s = [ width height 0 ].
       获取经过矩阵变换后的尺寸大小(宽高);
     */
    CG_EXTERN CGSize CGSizeApplyAffineTransform(CGSize size, CGAffineTransform t);
    
    /*
       获取经过矩阵变换后的rect; 
     */
    CG_EXTERN CGRect CGRectApplyAffineTransform(CGRect rect, CGAffineTransform t);
    
    

    4、重点理解:

    在所有transform中都是围绕锚点(anchorPoint)进行的,所有的基准都是以锚点为参照进行变换的!!!

    代码示例-3

    代码示例-3与代码示例-1相比,仅仅改变了锚点的位置(从(0.5, 0.5)改到了(0, 0)),下面我们看一下效果:

    效果示例-3

    可以看到旋转和缩放的参照点都成了视图的左上角了(即锚点位置)。

    相关文章

      网友评论

      • 没有名字就是我的名字:欢迎各路大神没事来这群里面吹吹技术的牛逼 聊聊技术的问题,超过100人改为付费群,且行且珍惜号:614194935

      本文标题:AffineTransform -> 仿射变换

      本文链接:https://www.haomeiwen.com/subject/umsucxtx.html