Core Graphics框架 :仿射变换与齐次坐标


Core Graphics框架中的图形变换


在Core Graphics框架图形绘制的时候,经常会有对图形进行平移、缩放、旋转这样的要求.那么我们该如何实现呢?这就需要Core Graphics框架中的CGAffineTransform(矩阵)这个结构体来进行实现了.下面我们就对CGAffineTransform这个矩阵结构体,进行逐一的说明.


CGAffineTransform与齐次坐标


首先,我们先看一下CGAffineTransform这个结构体是什么样子的,如下所示.

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

为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准.也就是z轴.是不发生改变的。接下来呢,我们就使用齐次坐标来表示这个结构体.如下所示.

|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|

那么平移、缩放、旋转是怎么执行的呢?其实很简单,这三种形式的变换不过是齐次坐标的几个特殊情况,下面我们就一一道来.

平移变换
条件: a = d = 1 ,b = c = 0.

条件如上所述,接下来我们看一下坐标 [X ,Y,1]与我们设定好的齐次坐标的叉积会发生什么样的变化.

               |1  0  0|

  [X,Y,  1]    |0  1  0|   =  [X + tx   ,  Y + ty  , 1] ;

                |tx ty 1|

那么的坐标就变成了 [X + tx , Y + ty , 1],与原坐标相比,z轴没发生任何的改变,但是x轴方向平移了tx个单位,y轴方向平移了ty个单位.

那么如果我们把这种特殊情况进行封装,我们就得到了我们的平移函数.

CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty)


缩放变换
条件: b = c = 0 ,tx = ty = 0.

如平移变换一致,我们把条件输入进去,看一下坐标 [X ,Y,1]与我们设定好的齐次坐标的叉积会发生什么样的变化.

               |a  0  0|

  [X,Y,  1]    |0  d  0|   =  [aX  ,  dY  ,1] ;

                |0 0 1|

那么的坐标就变成了[aX , dY ,1],与原坐标相比,z轴仍然没发生任何的改变,但是x轴方向缩放了a倍,y轴方向缩放了d倍.

那么如果我们把这种特殊情况进行封装,我们就得到了我们的缩放函数.注意一点的是使用缩放函数的时候,sx和sy如果不想让其改变就设置为1,而不是0.

GAffineTransformMakeScale(CGFloat sx, CGFloat sy)


旋转变换
条件 : tx=ty=0,a=cosɵ,b=sinɵ,c=-sinɵ,d=cosɵ

跟上面的两种情况一样,我们首先条件带入我们的齐次坐标里面,看一下结果如何.

               |cosɵ   sinɵ  0|

  [X,Y,  1]    |-sinɵ  cosɵ  0|   = [Xcosɵ - Ysinɵ ,   Xsinɵ + Ycosɵ , 1] ;

                |tx     ty    1|

这个时候,ɵ就是旋转的角度,逆时针为正,顺时针为负。

那么如果我们把这种特殊情况进行封装,我们就得到了我们的缩放函数.

CGAffineTransformMakeRotation(CGFloat angle)


CGAffineTransform的使用


上面,我们已经对仿射变换有了大体的了解,知道了它的原理,那么接下来我们就做一个简单Demo.来看一下在Core Graphics框架中是如何使用仿射变换函数的.

首先还是创建SDView继承与UIView类.

我们依然在drawInRect:这个方法中进行我们的操作.我们在方法中先在图形上下文中绘制一个矩形.代码如下.

    //获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();


    //创建路径
    CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), nil);
    
    
    //添加路径
    CGContextAddPath(context, path);
    
    //设置颜色
    CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);
    
    //绘制
    CGContextDrawPath(context, kCGPathFillStroke);

    //删除路径
    CGPathRelease(path);

接下来我们直接在ViewController中添加SDView这个视图.

#import "ViewController.h"
#import "SDView.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    SDView *view = [[SDView alloc]initWithFrame:self.view.frame];
    
    view.backgroundColor = [UIColor whiteColor];
    
    [self.view addSubview:view];
    
}

@end

效果如下.

上面绘制的矩形是没有经过任何图形变换的.接下来我们就在drawInRect:这个方法中创建三种仿射变换.代码如下.

    //创建平移变化结构体
    CGAffineTransform translationAffineTransform = CGAffineTransformMakeTranslation(100, 0);
    
    //创建缩放变化结构体
    CGAffineTransform scaleAffineTransform = CGAffineTransformMakeScale(3, 0);
    
    //创建缩放变化结构体
    CGAffineTransform rotationAffineTransform = CGAffineTransformMakeRotation(M_PI_2);

紧接着,我们就把创建路径这个代码替换成有仿射变换的路径.(当然了,我们要把多余的注释掉嗷~~)

//    //创建路径
//    CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), nil);
//    
    //创建路径(平移)
    CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), &translationAffineTransform);
    
    //创建路径(缩放)
    CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), &scaleAffineTransform);
    
    //创建路径(旋转)
    CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), &rotationAffineTransform);

下面我们就看一下三种仿射变换的效果图.

平移变换
缩放变换
旋转变换



Core Graphics框架仿射变换就说这么多了,后期,最后双手奉上Demo.

-->仿射变换Demo传送门💾

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

推荐阅读更多精彩内容