CGAffineTransform

在OC中,通过transform属性可以修改对象的平移、缩放比例和旋转角度

常用的创建transform结构体方法分两大类

(1) 创建“基于控件初始位置”的形变

CGAffineTransformMakeTranslation(平移)

CGAffineTransformMakeScale(缩放)

CGAffineTransformMakeRotation(旋转)

(2) 创建“基于transform参数”的形变

CGAffineTransformTranslate

CGAffineTransformScale

CGAffineTransformRotate


CGAffineTransformMake(a,b,c,d,tx,ty) 矩阵运算的原理

博客分类: iosios-animationios-drawing

简记:

CGAffineTransformMake(a,b,c,d,tx,ty)

ad缩放bc旋转tx,ty位移,基础的2D矩阵

公式

x=ax+cy+tx

y=bx+dy+ty

1.矩阵的基本知识:

struct CGAffineTransform

{

CGFloat a, b, c, d;

CGFloat tx, ty;

};

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

为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准。所以所有的变化都由前两列完成。

以上参数在矩阵中的表示为:

|a    b    0|

|c    d    0|

|tx  ty  1|

运算原理:原坐标设为(X,Y,1);

|a    b    0|

[X,Y,  1]      |c    d    0|    =    [aX + cY + tx  bX + dY + ty  1] ;

|tx    ty  1|

通过矩阵运算后的坐标[aX + cY + tx  bX + dY + ty  1],我们对比一下可知:

第一种:设a=d=1, b=c=0.

[aX + cY + tx  bX + dY + ty  1] = [X  + tx  Y + ty  1];

可见,这个时候,坐标是按照向量(tx,ty)进行平移,其实这也就是函数

CGAffineTransform CGAffineMakeTranslation(CGFloat tx,CGFloat ty)的计算原理。

第二种:设b=c=tx=ty=0.

[aX + cY + tx  bX + dY + ty  1] = [aX    dY  1];

可见,这个时候,坐标X按照a进行缩放,Y按照d进行缩放,a,d就是X,Y的比例系数,其实这也就是函数

CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)的计算原理。a对应于sx,d对应于sy。

第三种:设tx=ty=0,a=cosɵ,b=sinɵ,c=-sinɵ,d=cosɵ。

[aX + cY + tx  bX + dY + ty  1] = [Xcosɵ - Ysinɵ    Xsinɵ + Ycosɵ  1] ;

可见,这个时候,ɵ就是旋转的角度,逆时针为正,顺时针为负。其实这也就是函数

CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)的计算原理。angle即ɵ的弧度表示。

2.利用上面的变换写一个UIImage矩阵变换的例子:

下面是一个关于image的矩阵运算的例子,无外乎是运用以上三种变换的组合,达到所定义的效果

Java代码  收藏代码

//UIImageOrientation的定义,定义了如下几种变换

typedef enum

{

UIImageOrientationUp,            // default orientation

UIImageOrientationDown,          // 180 deg rotation

UIImageOrientationLeft,          // 90 deg CCW

UIImageOrientationRight,        // 90 deg CW

UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip

UIImageOrientationDownMirrored,  // horizontal flip

UIImageOrientationLeftMirrored,  // vertical flip

UIImageOrientationRightMirrored, // vertical flip

} UIImageOrientation;

//按照UIImageOrientation的定义,利用矩阵自定义实现对应的变换;

-(UIImage *)transformImage:(UIImage *)aImage

{

CGImageRef imgRef = aImage.CGImage;

CGFloat width = CGImageGetWidth(imgRef);

CGFloat height = CGImageGetHeight(imgRef);

CGAffineTransform transform = CGAffineTransformIdentity;

CGRect bounds = CGRectMake(0, 0, width, height);

CGFloat scaleRatio = 1;

CGFloat boundHeight;

UIImageOrientation orient = aImage.imageOrientation;

switch(UIImageOrientationLeftMirrored)

{

case UIImageOrientationUp:

transform = CGAffineTransformIdentity;

break;

case UIImageOrientationUpMirrored:

transform = CGAffineTransformMakeTranslation(width, 0.0);

transform = CGAffineTransformScale(transform, -1.0, 1.0); //沿y轴向左翻

break;

case UIImageOrientationDown:

transform = CGAffineTransformMakeTranslation(width, height);

transform = CGAffineTransformRotate(transform, M_PI);

break;

case UIImageOrientationDownMirrored:

transform = CGAffineTransformMakeTranslation(0.0, height);

transform = CGAffineTransformScale(transform, 1.0, -1.0);

break;

case UIImageOrientationLeft:

boundHeight = bounds.size.height;

bounds.size.height = bounds.size.width;

bounds.size.width = boundHeight;

transform = CGAffineTransformMakeTranslation(0.0, width);

transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);

break;

case UIImageOrientationLeftMirrored:

boundHeight = bounds.size.height;

bounds.size.height = bounds.size.width;

bounds.size.width = boundHeight;

transform = CGAffineTransformMakeTranslation(height, width);

transform = CGAffineTransformScale(transform, -1.0, 1.0);

transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);

break;

case UIImageOrientationRight: //EXIF = 8

boundHeight = bounds.size.height;

bounds.size.height = bounds.size.width;

bounds.size.width = boundHeight;

transform = CGAffineTransformMakeTranslation(height, 0.0);

transform = CGAffineTransformRotate(transform, M_PI / 2.0);

break;

case UIImageOrientationRightMirrored:

boundHeight = bounds.size.height;

bounds.size.height = bounds.size.width;

bounds.size.width = boundHeight;

transform = CGAffineTransformMakeScale(-1.0, 1.0);

transform = CGAffineTransformRotate(transform, M_PI / 2.0);

break;

default:

[NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

}

UIGraphicsBeginImageContext(bounds.size);

CGContextRef context = UIGraphicsGetCurrentContext();

if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {

CGContextScaleCTM(context, -scaleRatio, scaleRatio);

CGContextTranslateCTM(context, -height, 0);

}

else {

CGContextScaleCTM(context, scaleRatio, -scaleRatio);

CGContextTranslateCTM(context, 0, -height);

}

CGContextConcatCTM(context, transform);

CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);

UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return imageCopy;

}

2、

CGFloat width = CGRectGetWidth(btn.frame);

[UIView animateWithDuration:2 animations:^{

CGAffineTransform transform = CGAffineTransformIdentity;

transform = CGAffineTransformMakeTranslation(width, 0.0);

transform = CGAffineTransformScale(transform, -1.0, 1.0); //沿y轴向左翻

btn.transform = transform;

} completion:^(BOOL finished) {

}];

/**

*  CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)

*  abS缩放cd旋转txty移动

*

*  原坐标(X Y 1)

|a  b  0|

*  [X Y 1] |c  d  0| = [aX+cY+tx bX+dY+ty 1]

|tx ty 1|

*  例:

*  a=d=1, b=c=0.                              ————> [X  + tx  Y + ty  1] 平移

*  b=c=tx=ty=0.                                ————> [aX    dY  1];      缩放

*  tx=ty=0,a=cosɵ,b=sinɵ,c=-sinɵ,d=cosɵ      ————> [Xcosɵ - Ysinɵ    Xsinɵ + Ycosɵ  1] 旋转

*/

举个例子:

1、

[UIView animateWithDuration:1.0 animations:^{

//        btn.transform = CGAffineTransformMakeScale(2., 2.);

btn.transform = CGAffineTransformMake(2, 0, 0, 2, 0, 0);  // +/-效果不同

} completion:^(BOOL finished) {

[UIView animateWithDuration:1.0 animations:^{

//            btn.transform = CGAffineTransformMakeScale(1., 1.);

btn.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);

} completion:^(BOOL finished) {

}];

}];

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358

推荐阅读更多精彩内容