2013-12-11 27 views
3

對於動畫計時算法,我需要提供一條路徑作爲曲線。可能是兩端都有控制點的貝塞爾曲線。CGPath有沒有替代方法可以計算給定位置的路徑上的點?

問題是,似乎無法計算CGPath上的點,因爲CGPathRef是不透明的。此外,Apple沒有提供計算路徑上的點的機制。

是否有一個庫或工具類可以計算貝塞爾曲線或路徑上的點,對於路徑中間的0.5等給定位置?

或讓我改述一下:如果CGPath/CGPathRef使它變得不可能,因爲它是不透明的,而且如果你只關心貝塞爾曲線,有沒有一種方法可以計算路徑上的位置點?

+0

嗨,openfrog。就「CGPath/CGPathRef」而言,它意味着什麼「不透明」?我想,你不是在談論「不透明」。考慮到我知道控制點,開始點和結束點,我嘗試在CGPath上獲取點的問題同樣存在。 – Unheilig

回答

1

如果你已經有控制點的貝塞爾曲線,你想使用的定時功能(什麼,我認爲能CAAnimation),那麼你應該使用下面的函數來獲得相應的計時功能:

[CAMediaTimingFunction functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y] 

但是,如果您要做的是計算給定X位置的貝塞爾曲線的Y位置,則必須自己計算該位置。這裏是如何做到這一點參考:Bezier Curves

4

後面的貝塞爾曲線的數學居然是 「公正」:

start⋅(1-T) +3⋅c ⋅t(1-T) +3⋅c ⋅t2(1-T)+end⋅t

這意味着如果您知道,開始,結束和兩個控制點(c 和c ),則可以計算任意t(從0到1)的值。

它的值是點(如下圖),那麼你可以分別爲x和y做這些計算。

enter image description here

這是形式my explanation of Bézier paths here並更新橙色的圓爲滑塊改變(在JavaScript)的代碼只是這個(應該不會太難翻譯成Objective-C的或者乾脆C,但我太懶了):

var sx = 190; var sy = 80; // start 
var ex = 420; var ey = 250; // end 

var c1x = -30; var c1y = 350; // control point 1 
var c2x = 450; var c2y = -20; // control point 2 

var t = (x-minSliderX)/(maxSliderX-minSliderX); // t from 0 to 1 

var px = sx*Math.pow(1-t, 3) + 3*c1x*t*Math.pow(1-t, 2) + 3*c2x*Math.pow(t,2)*(1-t) + ex*Math.pow(t, 3); 
var py = sy*Math.pow(1-t, 3) + 3*c1y*t*Math.pow(1-t, 2) + 3*c2y*Math.pow(t,2)*(1-t) + ey*Math.pow(t, 3); 
// new point is at (px, py) 
+1

這是正確的,但值得注意的是'pow()'函數與手乘法相比非常慢。如果你需要計算許多點,它可能會產生嚴重的影響(我通常不鼓勵過早的優化,但pow()對於平方和立方體來說非常緩慢,以至於它真的值得擴展它所需的小小麻煩)。我在幾篇文章中討論了ObjC中的Bézier計算:http://robnapier.net/blog/fast-bezier-intro-701和http://robnapier.net/blog/faster-bezier-722。 –

+1

另一方面說明:沿Bézier移動不是線性的。 0.5會在中間,0。25將不會是它的四分之一。如果您需要順利地沿曲線移動,則必須計算曲線長度,這不是微不足道的。有關這種函數的示例,請參閱https://github.com/iosptl/ios6ptl/blob/master/ch26/CurvyText/CurvyText/CurvyTextView.m中的'offsetAtDistance:fromPoint:offset:' –

相關問題