CGAffineTransform 是對(duì)于仿射變換矩陣進(jìn)行了封裝赖临,而要理解仿射變換(affine transformation)先要理解線性變換(linear transformation)
線性變換
教材中的定義
設(shè)V, U 分別是n維和m維線性空間胞锰,T是一個(gè)從V到U的映射,如果T滿足
1.任意V中向量 α1兢榨、α2嗅榕,有T(α1 + α2) = T(α1)+T(α2)
2.任意V中向量 α,有T(λα) = λT(α)
那么顺饮,T就稱為從V到U的線性映射,或線性變換
簡(jiǎn)而言之線性變換就是把一個(gè)線性空間的向量映射到另一個(gè)線性空間去凌那,而且這個(gè)映射具備線性原則兼雄,即
1.兩個(gè)向量之和的映射 = 兩個(gè)向量映射的和
2.(向量 * 常數(shù)) 的映射 = (向量的映射) * 常數(shù)
根據(jù)這樣的定義可知線性變換的特點(diǎn)
1.直線經(jīng)過變換依然是直線
2.原點(diǎn)不變(T(0) = 0)
3.根據(jù)矩陣的性質(zhì),任何n維實(shí)數(shù)空間的線性變換都可以用矩陣來表示即 T(x) = Ax
二維空間內(nèi)的線性變換
當(dāng)V = U = 二維線性空間時(shí)帽蝶,就可以理解為二維空間內(nèi)部的坐標(biāo)變換
用矩陣表示為(采用與CGAffineTransform相同的矩陣赦肋,可能與教材給定的方式有差異,但本質(zhì)相同):
列出對(duì)應(yīng)的方程組:
二維空間內(nèi)的線性變換可以實(shí)現(xiàn)很多效果
旋轉(zhuǎn)
縮放
對(duì)稱
1.當(dāng) a=1, d=-1, b=c=0時(shí)
沿x軸對(duì)稱
2.當(dāng) a=-1, d=1, b=c=0時(shí)
沿y軸對(duì)稱
3.當(dāng) a=-1,d=-1, b=c=0時(shí)
原點(diǎn)對(duì)稱
4.當(dāng) a=d=0, b=c=1時(shí)
沿 y=x 對(duì)稱
錯(cuò)切(平行四邊形化)
1.當(dāng) a=d=1, b=0, c為任意 時(shí)
沿x方向錯(cuò)切
2.當(dāng) a=d=1, c=0, b為任意 時(shí)
沿y方向錯(cuò)切
注:以上均可通過 let transform = CGAffineTransform(a: a, b: b, c: c, d: d, tx: 0, ty: 0)來實(shí)現(xiàn)
仿射變換
CGAffineTransform 除了 a,b,c,d 還包含tx励稳,ty佃乘。之所以二維空間的變換要使用三維矩陣,是因?yàn)槎S空間線性變換沒辦法實(shí)現(xiàn)平移的效果驹尼,需要借助三維空間的線性變換趣避,再映射到二維空間,形成二維空間的平移效果扶欣。
維基百科的動(dòng)態(tài)圖鹅巍,較好的展示了這一點(diǎn)
CGAffineTransform
a b c d tx ty 常用含義整理
由上可知 tx,ty只負(fù)責(zé)平移料祠,而a,b,c,d在不同操作下具有不同含義
只有旋轉(zhuǎn)時(shí)
a = d = cosφ
b = sinφ
c = -sinφ
只有縮放時(shí)
a: x方向縮放系數(shù)
d: y方向縮放系數(shù)
旋轉(zhuǎn)與縮放復(fù)合時(shí)
復(fù)合情況下,當(dāng)前transfrom中 a,b,c,d 是多個(gè)矩陣相乘后的結(jié)果
縮放系數(shù):行列式值 ---- 科普原因
即:
public func scale() -> CGFloat{
let scale = sqrt(a*d - b*c)
return scale
}
旋轉(zhuǎn)弧度:
因?yàn)閺?fù)合情況下a為 scale 與 cosφ 的乘積澎羞,所以可得:
/// -π ~ π
public func rotate() -> CGFloat{
let scale = sqrt(a*d - b*c)
if scale == 0 {
return 0
}
var rotate = acos(a/scale)
//由于rotate >= 0 && <= π, 當(dāng)旋轉(zhuǎn)超過π或?yàn)樨?fù)時(shí)髓绽,要加入符號(hào)判斷
if (b < 0) {
rotate = -rotate
}
return rotate
}
transform, anchorPoint, frame
對(duì)transform進(jìn)行變換時(shí),frame會(huì)發(fā)生變化妆绞,但這種變化不是直接將frame這個(gè)長(zhǎng)方形內(nèi)的坐標(biāo)同時(shí)變換成新的frame顺呕,而是先在其 ****自身坐標(biāo)系**** 內(nèi)所有的點(diǎn)進(jìn)行transform變換,然后再更新到其frame的變化
而自身坐標(biāo)系的原點(diǎn)括饶,就是其anchorPoint株茶,因?yàn)閍nchorPoint默認(rèn)(0.5,0.5),也就是其中心點(diǎn)图焰。
縮放并改變anchorPoint后frame的變化
在這個(gè)transform進(jìn)行x, y 同時(shí)放大2倍的過程中启盛,其frame的變化
縮放前frame(137.5, 283.5, 100.0, 100.0)
縮放后frame(87.5, 233.5, 200.0, 200.0)
還是上面的view,現(xiàn)將其anchorPoint改為(0, 0)技羔,在對(duì)其進(jìn)行上面的x, y 放大2倍的過程僵闯,推算一下frame最終會(huì)變?yōu)槎嗌佟?/p>
frame的計(jì)算原理
frame.origin.x = position.x - anchorPoint.x * bounds.size.width
frame.origin.y = position.y - anchorPoint.y * bounds.size.height
1.ahchorPoint變?yōu)?(x: 0, y: 0)
2.anchorPoint改變不影響position,position = (x: 187.5, y:333.5)
3.由上述frame計(jì)算原理可得 frame = (187.5, 333.5, 100, 100)
4.因?yàn)槠渥陨碜鴺?biāo)系坐標(biāo)為(0,0,100,100),縮放后為(0,0,200,200), 轉(zhuǎn)化為frame = (187.5, 333.5, 200, 200)
運(yùn)行結(jié)果一致
縮放前frame(137.5, 283.5, 100.0, 100.0)
修改anchorPoint為0后的frame(187.5, 333.5, 100.0, 100.0)
縮放后frame(187.5, 333.5, 200.0, 200.0)
不改變anchorPoint而修改旋轉(zhuǎn)中心點(diǎn)的方式
在對(duì)transform進(jìn)行旋轉(zhuǎn)或縮放等操作時(shí)藤滥,修改anchorPoing可以修改旋轉(zhuǎn)或縮放的中心鳖粟,這是我們常用的操作,但是anchorPoint的修改直接會(huì)導(dǎo)致元素位置變化拙绊,所以做完transform變化后通常還要恢復(fù)anchorPoint向图。
要想transform中心點(diǎn)變化還不改變anchorPoint泳秀,可以通過先平移后旋轉(zhuǎn)從而達(dá)到和修改anchorPoint一樣的效果
/// 生成繞任意點(diǎn)旋轉(zhuǎn)的transfrom
/// - Parameters:
/// - radian: 旋轉(zhuǎn)弧度
/// - circleCenter: 旋轉(zhuǎn)中心
/// - viewCenter: 被旋轉(zhuǎn)view的中心
private func rotateTransform(radian:CGFloat, circleCenter:CGPoint, viewCenter: CGPoint) -> CGAffineTransform {
/// 轉(zhuǎn)化為將旋轉(zhuǎn)的view 自身的坐標(biāo)系
let x = circleCenter.x - viewCenter.x
let y = circleCenter.y - viewCenter.y
let transform = CGAffineTransform(a: cos(radian), b: sin(radian), c: -sin(radian), d: cos(radian), tx: x - x*cos(radian)+y*sin(radian), ty: y-x*sin(radian)-y*cos(radian))
return transform
}
具體效果
重點(diǎn)整理
- 二維線性變換能實(shí)現(xiàn)很多效果,如縮放榄攀,旋轉(zhuǎn)等晶默,這些變換使用二維矩陣就夠了,而CGAffineTransfrom使用三維矩陣的原因是航攒,二維空間下的線性變換無法實(shí)現(xiàn)平移磺陡,需要從三維的線性變換來實(shí)現(xiàn)二維的平移
- 仿射變換都是根據(jù)自身坐標(biāo)系來進(jìn)行,這個(gè)自身坐標(biāo)系以anchorPoint所指向的點(diǎn)為(0漠畜,0)币他,而不是直接使用和其frame一樣的坐標(biāo)系
- 靈活應(yīng)用 a,b,c,d,tx,ty
- 了解frame的計(jì)算方式,以及transform如何影響frame