De Casteljau算法
題目 在Bezier曲線上找到點:De Casteljau算法
翻譯文章來自http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html
在貝塞爾曲線繪制完成后,下一個重要的任務是選定特定u的情況下在曲線上找到點C(u)。一個簡單的方法是把u插到每一個基函數上,計算每個其與基函數的乘積以及其相應的控制頂點,最后將其相加。雖然這種方法很好,但是缺乏數值穩定性(例如在計算Bernstein多項式的時候可能引進數值(numerical errors)誤差)。
在下文中,我們僅僅記下控制點的數字。例如00對應控制點P0,01對應P1,...,0i對應Pi,...,0n對應Pn。因此在這些數字中0s表示初始的或者是第0次迭代。在之后,0被其他數字1,2,3代替表示第1,2,3次迭代,等等。
De Casteljau算法的基本觀點是選擇在AB中的一個點C,C將AB分為u:1-u(A到C的距離與AB之間的距離之比是u),讓我們找到決定C在哪里的方法
從A到B的向量是B-A。因為u是在0和1之間的比率,點C位于u(B-A)。將A的位置加以考慮,點C為A+u(B-A)=(1-u)A+uB。因此,對于給定的u,(1-u)A+uB是在A和B之間的點C,將AB分為u:1-u的兩段
De Casteljau算法的想法如下。假設我們想要找到C(u),u在[0,1]中。由第一個多段線00-01-02-03...-0n開始,利用上面的法則找到在線段上的點1i,1i在0i到0(i+1)的連線上并且將這段線分為u:1-u的兩部分。依次地,我們可以得到n個點10,11,12,...,1(n-1),他們定義了一個新的多段線(polyline),一共有n-1段
在上圖中,u是0.4,10是在00和01的線段(leg),11是在01和02的線段,...,并且14是在04到05的線段,所有的新點都由藍色的表示。
新點由1i進行標記,再次利用上面的規則我們可以得到第二個多段線,具有n-1個點(20,21,...,2(n-2))和n-2條邊。從這個多段線開始,進行第三次,得到新的多段線,由n-2個點30,31,...,3(n-3)和n-3條邊組成。重復這個過程n次得到一個點n0,Casteljau已經證明在曲線上的點C(u)對應u
以上圖舉例,20是在10和11上將這段線分為u:1-u的點,類似地選取21在11和12上,22在12和13上,23在13和14上.第三個多段線是20,21,22,23.第三個多段線有四個點和三條邊。繼續做得到30,31,32組成的多段線,這是第四個多段線。繼續得到有40和41組成的線段,再做一次得到50,為點C(0.4)。
這是de Casteljau算法的幾何解釋,是在曲線設計中最漂亮(elegant)的結果之一。
實際計算
給定了de Casteljau的幾何解釋之后,我們現在展示一個計算方法,由下圖
首先,在如圖中的最左邊一列是給定的控制點。對于每一對臨近的控制點,可以畫出一條右上方和右下方的箭頭,并且在兩個箭頭的交點處寫下一個新點。例如相鄰的兩個點分別為ij 和i(j+1),新點是(i+1)j,右下方(相對應的左下方)的箭頭表示將其尾數ij(相對應的為i(j+1))乘以1-u(相對應的乘以u),新的點是兩個的和。
因此,從初始的第0列開始,我們計算第1列。之后從第1列得到第2列。最終,在n次計算之后我們最終到達了一個單個的點n0并且這個點就是在曲線上的點。下面的算法總結了上面我們討論的內容,輸入的是具有n+1個點的數列P和在0到1之間的u,最終得到在Bezier曲線上的點C(u)
Input: array P[0:n] of n+1 points and real number u in [0,1] Output: point on curve, C(u) Working: point array Q[0:n] for i := 0 to n do Q[i] := P[i]; // save input for k := 1 to n do for i := 0 to n - k do Q[i] := (1 - u)Q[i] + u Q[i + 1]; return Q[0];一個遞歸關系
上面的計算過程可以用遞歸的方法表示,對于j=0,1,...,n用P0,j表示Pj,也就是P0,j是第0列的第j項元素,在第i列計算第j項如下
元素Pi,j是(1-u)Pi-1,j(左上方元素和 uPi-1,j+1(左下方元素)的和,最終的結果(在曲線上的點)是Pn,0.在這種想法的基礎上,我們可以快速得到以下過程
function deCasteljau(i,j) begin if i = 0 then return P0,j else return (1-u)* deCasteljau(i-1,j) + u* deCasteljau(i-1,j+1) end這個過程看起來簡單,表達上也很簡練,但是效率卻不高。因為我們想要對于Pn,0計算deCasteljau(n,0) ,我們要分別對Pn-1,0計算deCasteljau(n-1,0),0,對Pn-1,1計算deCasteljau(n-1,1)
再考慮計算deCasteljau(n-1,0)。分為對于Pn-2,0計算deCasteljau(n-2,0),和對于Pn-2,1計算deCasteljau(n-2,1)。對于deCasteljau(n-1,1)也是分為兩部分如上圖所示。因此deCasteljau(n-2,1)被計算了兩遍,如果我們擴展這些函數計算,我們會發現對于Pi,j的計算重復了很多遍,而不是僅僅計算了一遍。事實上,上面的計算和計算Fibonacci數列的第n項是類似的
function Fibonacci(n) begin if n = 0 or n = 1 then return 1 elsereturn Fibonacci (n-1) + Fibonacci (n-2) end為了計算 Fibonacci( n)函數被調用了指數次,因此上面的de Casteljau算法對于直接的實現來說是不合適的,雖說代碼看上去比較簡潔。
一個有趣的觀察
de Casteljau算法的三角形計算方法提供了一種有趣的現象,舉一個例子,八個控制點00,01,...,07組成的7階Bezier曲線。選擇控制點列中的連續序列,對于給定的u,怎樣計算其在Bezier曲線上對應的點呢?事實上,如果利用de Casteljau算法,發現在曲線上的點就是等邊三角形的頂點!其底是選擇的連續點列。
舉例來說,如果我們選擇02,03,04,05,其對應于u這四個控制頂點的曲線上的點就是32,就是上圖中的藍色三角形,如果選擇11,12,13,在曲線上的點就是31,如黃色三角形。如果選擇30,31,32,33和34,那么在曲線上的點就是70.
也是同樣的原因,70在由60和61組成的Bezier曲線上。同樣地,也是50,51和52上的點,也是40,41,42,43.一般地,如果我們選擇一個點并且如上所示畫一個等邊三角形,其底上的控制點就是被選擇用來計算的點。
總結
以上是生活随笔為你收集整理的De Casteljau算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [vue] 说说你对keep-alive
- 下一篇: 保姆级的Arduino循迹小车研发日志及