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);
下面我們就看一下三種仿射變換的效果圖.