
Core Graphics框架中的圖形變換
在Core Graphics框架圖形繪制的時(shí)候,經(jīng)常會(huì)有對(duì)圖形進(jìn)行平移、縮放、旋轉(zhuǎn)這樣的要求.那么我們?cè)撊绾螌?shí)現(xiàn)呢?這就需要Core Graphics框架中的CGAffineTransform(矩陣)這個(gè)結(jié)構(gòu)體來進(jìn)行實(shí)現(xiàn)了.下面我們就對(duì)CGAffineTransform這個(gè)矩陣結(jié)構(gòu)體,進(jìn)行逐一的說明.

CGAffineTransform與齊次坐標(biāo)
首先,我們先看一下CGAffineTransform這個(gè)結(jié)構(gòu)體是什么樣子的,如下所示.
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
為了把二維圖形的變化統(tǒng)一在一個(gè)坐標(biāo)系里,引入了齊次坐標(biāo)的概念,即把一個(gè)圖形用一個(gè)三維矩陣表示,其中第三列總是(0,0,1),用來作為坐標(biāo)系的標(biāo)準(zhǔn).也就是z軸.是不發(fā)生改變的。接下來呢,我們就使用齊次坐標(biāo)來表示這個(gè)結(jié)構(gòu)體.如下所示.
|a b 0|
|c d 0|
|tx ty 1|
現(xiàn)在我們就看一下用齊次坐標(biāo)是如何表示一個(gè)坐標(biāo)的仿射變換的,假設(shè)現(xiàn)在有坐標(biāo) [X ,Y,1],運(yùn)算原理如下所示.
|a b 0|
[X,Y, 1] |c d 0| = [aX + cY + tx bX + dY + ty 1] ;
|tx ty 1|
那么平移、縮放、旋轉(zhuǎn)是怎么執(zhí)行的呢?其實(shí)很簡單,這三種形式的變換不過是齊次坐標(biāo)的幾個(gè)特殊情況,下面我們就一一道來.
平移變換
條件: a = d = 1 ,b = c = 0.
條件如上所述,接下來我們看一下坐標(biāo) [X ,Y,1]與我們?cè)O(shè)定好的齊次坐標(biāo)的叉積會(huì)發(fā)生什么樣的變化.
|1 0 0|
[X,Y, 1] |0 1 0| = [X + tx , Y + ty , 1] ;
|tx ty 1|
那么的坐標(biāo)就變成了 [X + tx , Y + ty , 1],與原坐標(biāo)相比,z軸沒發(fā)生任何的改變,但是x軸方向平移了tx個(gè)單位,y軸方向平移了ty個(gè)單位.
那么如果我們把這種特殊情況進(jìn)行封裝,我們就得到了我們的平移函數(shù).
CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty)
縮放變換
條件: b = c = 0 ,tx = ty = 0.
如平移變換一致,我們把條件輸入進(jìn)去,看一下坐標(biāo) [X ,Y,1]與我們?cè)O(shè)定好的齊次坐標(biāo)的叉積會(huì)發(fā)生什么樣的變化.
|a 0 0|
[X,Y, 1] |0 d 0| = [aX , dY ,1] ;
|0 0 1|
那么的坐標(biāo)就變成了[aX , dY ,1],與原坐標(biāo)相比,z軸仍然沒發(fā)生任何的改變,但是x軸方向縮放了a倍,y軸方向縮放了d倍.
那么如果我們把這種特殊情況進(jìn)行封裝,我們就得到了我們的縮放函數(shù).注意一點(diǎn)的是使用縮放函數(shù)的時(shí)候,sx和sy如果不想讓其改變就設(shè)置為1,而不是0.
GAffineTransformMakeScale(CGFloat sx, CGFloat sy)
旋轉(zhuǎn)變換
條件 : tx=ty=0,a=cos?,b=sin?,c=-sin?,d=cos?
跟上面的兩種情況一樣,我們首先條件帶入我們的齊次坐標(biāo)里面,看一下結(jié)果如何.
|cos? sin? 0|
[X,Y, 1] |-sin? cos? 0| = [Xcos? - Ysin? , Xsin? + Ycos? , 1] ;
|tx ty 1|
這個(gè)時(shí)候,?就是旋轉(zhuǎn)的角度,逆時(shí)針為正,順時(shí)針為負(fù)。
那么如果我們把這種特殊情況進(jìn)行封裝,我們就得到了我們的縮放函數(shù).
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransform的使用
上面,我們已經(jīng)對(duì)仿射變換有了大體的了解,知道了它的原理,那么接下來我們就做一個(gè)簡單Demo.來看一下在Core Graphics框架中是如何使用仿射變換函數(shù)的.
首先還是創(chuàng)建SDView繼承與UIView類.

我們依然在drawInRect:這個(gè)方法中進(jìn)行我們的操作.我們?cè)诜椒ㄖ邢仍趫D形上下文中繪制一個(gè)矩形.代碼如下.
//獲取圖形上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//創(chuàng)建路徑
CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), nil);
//添加路徑
CGContextAddPath(context, path);
//設(shè)置顏色
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);
//繪制
CGContextDrawPath(context, kCGPathFillStroke);
//刪除路徑
CGPathRelease(path);
接下來我們直接在ViewController中添加SDView這個(gè)視圖.
#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
效果如下.

上面繪制的矩形是沒有經(jīng)過任何圖形變換的.接下來我們就在drawInRect:這個(gè)方法中創(chuàng)建三種仿射變換.代碼如下.
//創(chuàng)建平移變化結(jié)構(gòu)體
CGAffineTransform translationAffineTransform = CGAffineTransformMakeTranslation(100, 0);
//創(chuàng)建縮放變化結(jié)構(gòu)體
CGAffineTransform scaleAffineTransform = CGAffineTransformMakeScale(3, 0);
//創(chuàng)建縮放變化結(jié)構(gòu)體
CGAffineTransform rotationAffineTransform = CGAffineTransformMakeRotation(M_PI_2);
緊接著,我們就把創(chuàng)建路徑這個(gè)代碼替換成有仿射變換的路徑.(當(dāng)然了,我們要把多余的注釋掉嗷~~)
// //創(chuàng)建路徑
// CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), nil);
//
//創(chuàng)建路徑(平移)
CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), &translationAffineTransform);
//創(chuàng)建路徑(縮放)
CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), &scaleAffineTransform);
//創(chuàng)建路徑(旋轉(zhuǎn))
CGPathRef path = CGPathCreateWithRect(CGRectMake(100, 100, 100, 100), &rotationAffineTransform);
下面我們就看一下三種仿射變換的效果圖.


