如何理解CGAffineTransform

作者: xFerris | 来源:发表于2016-04-06 12:29 被阅读1990次

    文章已发布在我的博客上,如需转载,请注明原文出处

    CGAffineTransform

    A structure for holding an affine transformation matrix.

    以上是它的定义,其实就是一个矩阵的结构体,经常用于动画,形状变换。
    包含如下参数:

    struct CGAffineTransform { CGFloat a; CGFloat b; CGFloat c; CGFloat d; CGFloat tx; CGFloat ty; }; typedef struct CGAffineTransform CGAffineTransform;  
    

    下面直观的描述这个这个矩阵和坐标之间的关系。

    一个实验

    • 给一个UIImageView添加手势
        //zoom手势
        UIPinchGestureRecognizer* zoomer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(editImageWithZoom:)];
        
        UIRotationGestureRecognizer* rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(editImageWithRotation:)];
        [imageView addGestureRecognizer:zoomer];
        
        [imageView addGestureRecognizer:rotation];
      
    
    • 手势实现方法
    //缩放
    -(void)editImageWithZoom:(UIPinchGestureRecognizer*)sender
    {
        CGAffineTransform transform= CGAffineTransformScale(originTransform, sender.scale, sender.scale);
        imageView.transform=transform;
    }
    //旋转
    -(void)editImageWithRotation:(UIRotationGestureRecognizer*)sender
    {
        CGAffineTransform transfrom = CGAffineTransformRotate(originTransform, sender.rotation);
        imageView.transform=transfrom;
    }
    

    其中的两个方法CGAffineTransformScaleCGAffineTransformRotate是生成旋转和缩放的矩阵,当然也可以直接使用通用方法

    CGAffineTransform CGAffineTransformMake ( CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty );
    

    生成对应的矩阵。

    • 继续变换

    不修改任何代码,继续缩放和旋转。会发现每次都重新归位后旋转。
    原来是CGAffineTransformIdentity这个常量搞的鬼。
    每一次的rotatescale都是在这个常量的基础上变换的。


    这个是它的定义。
    解决这个问题只要在手势代码中加入
        if(sender.state==UIGestureRecognizerStateEnded || sender.state==UIGestureRecognizerStateCancelled)
        {
            //结束手势
            originTransform=imageView.transform;
        }
    

    其中的originTransform可以定义为成员变量,初始化代码。

    originTransform = CGAffineTransformIdentity;
    
    • 坐标变换之后出现的问题

      意识到CGAffineTransform所做的变换其实是对坐标系做的变换。因此变换完以后使用平移操作会发现坐标系变换以后产生的影响。解决方案:

    • 取父view的坐标系,更改imageView.center,因为不论是scale还是rotationcenter的点是不变的。

    获取变换后的参数

    变换以后需要取得变换以后的scalerotation
    打变量观察。

    (lldb) po transistion
     (a = 0.69003591274966281, b = -1.6204680103221447, c = 1.6204680103221447, d = 0.69003591274966281, tx = 0, ty = 0)  
    

    其中scale是(双指缩放sx=sy):


    rotation是:

    联合作用在单位对角矩阵上:可以得到最终的transfrom:

    可以解得:
    好吧根本解不出来。另寻他路。

    打算用成员变量接受每一次旋转和缩放后的参数。
    打出每一次旋转和缩放操作的scalerotation。发现每一次都是重新从1和0开始计算。
    于是简单了,在每一次手势结束的时候加上原来的参数。

    -(void)editImageWithRotation:(UIRotationGestureRecognizer*)sender
    {
    
        CGAffineTransform transfrom = CGAffineTransformRotate(originTransform, sender.rotation);
        imageView.transform=transfrom;
       // NSLog(@"%lf",sender.rotation);
        if(sender.state==UIGestureRecognizerStateEnded || sender.state==UIGestureRecognizerStateCancelled)
        {
            //结束手势
            radians = radians+sender.rotation;
            originTransform=imageView.transform;
        }
    }
    

    scale类似方法获得。
    输出最后imageViewframe和最开始的frame

    frame = (247.357 307.2; 273.285 409.6)  //最初的
    frame = (142.016 271.144; 483.968 481.711)  //变换后的
    r = 0.79710480433663233  //旋转参数
    

    swift的牛逼的playground下调试

    let r = 0.79710480433663233
    let w = 273.285
    let h = 409.6
    let nw = h*cos(r)+w*sin(r)
    let nh = h*sin(r)+w*cos(r)
    

    发现rect旋转后的rect其实是这样:


    所以要获取用户变换以后的图片,可以这么来。
        UIImage* editedImge = [image imageByScalingToSize:CGSizeMake(originRect.size.width*scale, originRect.size.height*scale)];
        editedImge = [editedImge imageRotatedByRadians:rotation];
        
        //获取最终点的坐标
        [editedImge drawInRect:rect];
    

    大功告成。

    相关文章

      网友评论

        本文标题:如何理解CGAffineTransform

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