前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何理解CGAffineTransform

如何理解CGAffineTransform

作者头像
xferris
发布2018-06-01 15:38:57
1.1K0
发布2018-06-01 15:38:57
举报
文章被收录于专栏:慎独慎独
CGAffineTransform

A structure for holding an affine transformation matrix.

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

代码语言:javascript
复制
struct CGAffineTransform { CGFloat a; CGFloat b; CGFloat c; CGFloat d; CGFloat tx; CGFloat ty; }; typedef struct CGAffineTransform CGAffineTransform;  

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

一个实验
  • 给一个UIImageView添加手势
代码语言:javascript
复制
    //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];
  • 手势实现方法
代码语言:javascript
复制
//缩放
-(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是生成旋转和缩放的矩阵,当然也可以直接使用通用方法

代码语言:javascript
复制
CGAffineTransform CGAffineTransformMake ( CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty );

生成对应的矩阵。

  • 继续变换

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

这个是它的定义。 解决这个问题只要在手势代码中加入

代码语言:javascript
复制
    if(sender.state==UIGestureRecognizerStateEnded || sender.state==UIGestureRecognizerStateCancelled)
    {
        //结束手势
        originTransform=imageView.transform;
    }

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

代码语言:javascript
复制
originTransform = CGAffineTransformIdentity;
  • 坐标变换之后出现的问题 意识到CGAffineTransform所做的变换其实是对坐标系做的变换。因此变换完以后使用平移操作会发现坐标系变换以后产生的影响。解决方案:
  • 取父view的坐标系,更改imageView.center,因为不论是scale还是rotationcenter的点是不变的。
获取变换后的参数

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

代码语言:javascript
复制
(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开始计算。 于是简单了,在每一次手势结束的时候加上原来的参数。

代码语言:javascript
复制
-(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

代码语言:javascript
复制
frame = (247.357 307.2; 273.285 409.6)  //最初的
frame = (142.016 271.144; 483.968 481.711)  //变换后的
r = 0.79710480433663233  //旋转参数

swift的牛逼的playground下调试

代码语言:javascript
复制
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其实是这样:

所以要获取用户变换以后的图片,可以这么来。

代码语言:javascript
复制
    UIImage* editedImge = [image imageByScalingToSize:CGSizeMake(originRect.size.width*scale, originRect.size.height*scale)];
    editedImge = [editedImge imageRotatedByRadians:rotation];
    
    //获取最终点的坐标
    [editedImge drawInRect:rect];

大功告成。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CGAffineTransform
  • 一个实验
  • 获取变换后的参数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档