Core Graphics框架 :仿射變換與齊次坐標(biāo)


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

下面我們就看一下三種仿射變換的效果圖.

平移變換
縮放變換
旋轉(zhuǎn)變換



Core Graphics框架仿射變換就說這么多了,后期,最后雙手奉上Demo.

-->仿射變換Demo傳送門??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容