我們做圖形編輯的時(shí)候南缓,做了一個(gè)ShapeOperator類來(lái)操作圖形目锭,里面存儲(chǔ)了圖形的尺寸位置和泌、旋轉(zhuǎn)角度等信息村缸,可以生成貝塞爾曲線,將其賦值給 CAShapeLayer即可完成渲染
旋轉(zhuǎn)
SO上找到了操作貝塞爾曲線旋轉(zhuǎn)的最佳實(shí)踐:https://stackoverflow.com/questions/13738364/rotate-cgpath-without-changing-its-position
- 針對(duì)某個(gè)旋轉(zhuǎn)武氓,先以圖形中心點(diǎn)的負(fù)值做移動(dòng)梯皿,將中心點(diǎn)移動(dòng)到“視圖”左上角,再做旋轉(zhuǎn)县恕,然后再移動(dòng)回來(lái)东羹。
- 上面涉及三次 transform, 通過(guò) transformConcat連接忠烛,計(jì)算出最終 transfrom属提,賦值給貝塞爾曲線的 transform 屬性
平移
直接改變控制點(diǎn)即可
編輯控制點(diǎn)
以矩形為例,矩形有四個(gè)控制點(diǎn)美尸,即幾個(gè)角冤议,如果沒(méi)有旋轉(zhuǎn),拖動(dòng)任意控制點(diǎn)就能改變圖形的大小师坎,也很直觀恕酸,但是增加了旋轉(zhuǎn)以后,復(fù)雜度陡然提升
矩形的表示
- 起始點(diǎn) (x, y)
- 寬度 width
- 高度 height
- 旋轉(zhuǎn)角度 rotation
控制點(diǎn)轉(zhuǎn)換
- 如果沒(méi)有旋轉(zhuǎn)的圖形胯陋,改變的控制點(diǎn)蕊温,很容易對(duì)應(yīng)出起始點(diǎn)和寬高的改變,比如移動(dòng)矩形左上角遏乔,就是把起始點(diǎn)變成拖動(dòng)后的點(diǎn)义矛,對(duì)應(yīng)增加寬高
- 如果我們?cè)谝粋€(gè)旋轉(zhuǎn)了一定角度的圖形上,拖動(dòng)控制點(diǎn)盟萨,我們需要知道這個(gè)控制點(diǎn)到底如何影響上面的尺寸位置的症革,拖動(dòng)后的點(diǎn)的坐標(biāo),是未旋轉(zhuǎn)的控制點(diǎn)位置鸯旁,追加了旋轉(zhuǎn)角度后的坐標(biāo)
- 所以第一步是去除旋轉(zhuǎn)的影響噪矛,iOS 為我們提供了 CGPoint 的 transform 變換的計(jì)算方法
CGPointApplyAffineTransform
- 上面旋轉(zhuǎn)章節(jié)提到,做旋轉(zhuǎn)需要三次 transform铺罢,把它 concat 后的最終 transfrom 做
CGAffineTransformInvert
艇挨,再應(yīng)用給新的控制點(diǎn),就得到了矩形未旋轉(zhuǎn)時(shí)的新控制點(diǎn)位置韭赘,這就很容易把對(duì)應(yīng)的起始點(diǎn)和寬高計(jì)算出來(lái)了缩滨,然后再把圖形旋轉(zhuǎn)到對(duì)應(yīng)角度。 - 但是旋轉(zhuǎn)以后,和以前的圖形就不對(duì)齊了脉漏,這是個(gè)大坑苞冯,什么叫對(duì)齊?下面詳細(xì)說(shuō)
有旋轉(zhuǎn)的控制點(diǎn)變換追加平移
- 我們插入了下面的圖形侧巨,邊長(zhǎng) a舅锄,圖形中心點(diǎn) (x, y)
- 然后旋轉(zhuǎn)這個(gè)圖形到下圖,
- 接著拖動(dòng)圖形最下面的這個(gè)頂點(diǎn)司忱,讓圖形變大成邊長(zhǎng)b皇忿,我們期望的是下圖的效果
想達(dá)到上面的效果,我們有兩種途徑:
- 旋轉(zhuǎn)中心點(diǎn)不變坦仍,僅改變邊長(zhǎng)尺寸鳍烁,這樣我們?cè)谧鰣D形旋轉(zhuǎn)的時(shí)候,先對(duì)圖形進(jìn)行(-x, -y)的移動(dòng)繁扎,然后旋轉(zhuǎn)幔荒,再進(jìn)行 (x, y) 的移動(dòng),就能滿足上圖的效果(僅最底下的控制點(diǎn)變化了梳玫,其它邊以及頂部控制點(diǎn)與原先重合)铺峭。但是這樣有一個(gè)問(wèn)題,下次旋轉(zhuǎn)的時(shí)候汽纠,就不是沿著圖形中心點(diǎn)旋轉(zhuǎn)了,不過(guò)這個(gè)思路能幫我們找到正確答案
- 始終保持圖形中心點(diǎn)旋轉(zhuǎn)傀履。但是虱朵,因?yàn)榫庉嫼螅呴L(zhǎng)從 a 變成 b 钓账,圖形中心點(diǎn)會(huì)變成 (x', y')碴犬,那旋轉(zhuǎn)以后,圖形的頂點(diǎn)和其它邊就沒(méi)法與原先重合梆暮,而是像下圖
如果想達(dá)成期望的效果服协,在編輯圖形的時(shí)候,還要對(duì)圖形進(jìn)行平移啦粹,這樣旋轉(zhuǎn)以后就能使頂部的點(diǎn)與原先重合
我們按途徑1偿荷,以不變旋轉(zhuǎn)中心點(diǎn)的方式旋轉(zhuǎn)以后,圖形的中心點(diǎn)變成了 (x", y")唠椭,可以從下圖看到跳纳,(x", y") 與 (x', y') 存在平移,而此平移的變化由來(lái)贪嫂,就是以 (x, y) 為中心寺庄,將(x', y')旋轉(zhuǎn)圖形所旋轉(zhuǎn)的角度,變到了(x", y") ,移動(dòng)量就是 (x" - x', y" - y')
這樣斗塘,在編輯的時(shí)候赢织,計(jì)算編輯前后的中心點(diǎn)變化,并應(yīng)用上面的變換馍盟,得到圖形需要平移的量于置,追加給圖形,就可以達(dá)到預(yù)期的效果了
總結(jié)
圖形編輯朽合,有時(shí)候看起來(lái)很簡(jiǎn)單直觀的事情俱两,在實(shí)際代碼上,就會(huì)非常困難曹步,最近在做曲線的旋轉(zhuǎn)宪彩,又是一個(gè)大坑,因?yàn)榍€的起始點(diǎn)讲婚,終點(diǎn)尿孔、控制點(diǎn)三個(gè)點(diǎn),位置的不同筹麸,決定了曲線的形狀活合,拖動(dòng)終點(diǎn)或起點(diǎn)的時(shí)候,三個(gè)點(diǎn)都會(huì)變化物赶,而且一會(huì)正一會(huì)負(fù)白指,需要根據(jù)象限分別判斷曲線是凸的還是凹的,頭大啊酵紫。告嘲。