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;
}
其中的两个方法CGAffineTransformScale
和CGAffineTransformRotate
是生成旋转和缩放的矩阵,当然也可以直接使用通用方法
CGAffineTransform CGAffineTransformMake ( CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty );
生成对应的矩阵。
- 继续变换
不修改任何代码,继续缩放和旋转。会发现每次都重新归位后旋转。
原来是CGAffineTransformIdentity
这个常量搞的鬼。
每一次的rotate
和scale
都是在这个常量的基础上变换的。
这个是它的定义。
解决这个问题只要在手势代码中加入
if(sender.state==UIGestureRecognizerStateEnded || sender.state==UIGestureRecognizerStateCancelled)
{
//结束手势
originTransform=imageView.transform;
}
其中的originTransform
可以定义为成员变量,初始化代码。
originTransform = CGAffineTransformIdentity;
-
坐标变换之后出现的问题
意识到
CGAffineTransform
所做的变换其实是对坐标系做的变换。因此变换完以后使用平移操作会发现坐标系变换以后产生的影响。解决方案: 取父view的坐标系,更改
imageView.center
,因为不论是scale
还是rotation
,center
的点是不变的。
获取变换后的参数
变换以后需要取得变换以后的scale
和rotation
。
打变量观察。
(lldb) po transistion
(a = 0.69003591274966281, b = -1.6204680103221447, c = 1.6204680103221447, d = 0.69003591274966281, tx = 0, ty = 0)
其中scale
是(双指缩放sx=sy):
rotation
是:联合作用在单位对角矩阵上:可以得到最终的
transfrom
:可以解得:
好吧根本解不出来。另寻他路。
打算用成员变量接受每一次旋转和缩放后的参数。
打出每一次旋转和缩放操作的scale
和rotation
。发现每一次都是重新从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
类似方法获得。
输出最后imageView
的frame
和最开始的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];
大功告成。