1. 程式人生 > >貝塞爾曲線

貝塞爾曲線

線性 數值 int 優化 連續 多項式 三次 繪制 http

在數學的數值分析領域中,貝塞爾曲線(英語:Bézier curve)是電腦圖形學中相當重要的參數曲線。更高維度的廣泛化貝塞爾曲線就稱作貝塞爾曲面,其中貝塞爾三角是一種特殊的實例。

貝塞爾曲線於1962年,由法國工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發表,他運用貝塞爾曲線來為汽車的主體進行設計。貝塞爾曲線最初由Paul de Casteljau於1959年運用de Casteljau算法開發,以穩定數值的方法求出貝塞爾曲線。

線性貝塞爾曲線[編輯]

給定點P0P1,線性貝塞爾曲線只是一條兩點之間的直線。這條線由下式給出:

  • 技術分享

且其等同於線性插值。

線性貝塞爾曲線函數中的t會經過由P0P1Bt)所描述的曲線。例如當t=0.25時,Bt)即一條由點P0P1路徑的四分之一處。就像由0至1的連續tBt)描述一條由P0P1的直線。

技術分享

二次方貝塞爾曲線[編輯]

二次方貝塞爾曲線的路徑由給定點P0P1P2的函數Bt)追蹤:

  • 技術分享

TrueType字型就運用了以貝塞爾樣條組成的二次貝塞爾曲線。

為建構二次貝塞爾曲線,可以中介點Q0Q1作為由0至1的t

  • P0P1的連續點Q0,描述一條線性貝塞爾曲線。

  • P1P2的連續點Q1,描述一條線性貝塞爾曲線。

  • Q0Q1的連續點Bt),描述一條二次貝塞爾曲線。

  • 技術分享 技術分享

三次方貝塞爾曲線[編輯]

P0P1P2P3四個點在平面或在三維空間中定義了三次方貝塞爾曲線。曲線起始於P0走向P1,並從P2的方向來到P3。一般不會經過P1P2;這兩個點只是在那裏提供方向資訊。P0P1之間的間距,決定了曲線在轉而趨進P3之前,走向P2方向的“長度有多長”。

曲線的參數形式為:

  • 技術分享

現代的成象系統,如PostScript、Asymptote和Metafont,運用了以貝塞爾樣條組成的三次貝塞爾曲線,用來描繪曲線輪廓。

技術分享 技術分享

對於四次曲線,可由線性貝塞爾曲線描述的中介點Q0Q1Q2Q3,由二次貝塞爾曲線描述的點R

0R1R2,和由三次貝塞爾曲線描述的點S0S1所建構:

技術分享 技術分享

程式範例

技術分享

曲線的計算可在曲線陣列上將相連點畫上直線——點越多,曲線越平滑。

在部分架構中,下以程式碼也可由動態規劃進行最優化。舉例來說,dt是一個常數,cx * t則等同於每次反復就修改一次常數。經反復應用這種最優化後,循環可被重寫為沒有任何乘法(雖然這個過程不是穩定數值的)。

/*
 產生貝塞爾曲線的算法
*/
 typedef struct{
    float x;
    float y;}Point2D;
 /*
  cp 在此是四個元素的數組: 
  cp[0] 為起點,或上圖中的 P0 
  cp[1] 為第一控制點,或上圖中的 P1 
  cp[2] 為第二控制點,或上圖中的 P2 
  cp[3] 為結束點,或上圖中的 P3 
  t 為參數值,0 <= t <= 1
*/
 Point2D PointOnCubicBezier( Point2D* cp, float t ){
    float   ax, bx, cx;
    float   ay, by, cy;
    float   tSquared, tCubed;
    Point2D result;
 
    /*計算多項式系數 */
 
    cx = 3.0 * (cp[1].x - cp[0].x);
    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    ax = cp[3].x - cp[0].x - cx - bx;
 
    cy = 3.0 * (cp[1].y - cp[0].y);
    by = 3.0 * (cp[2].y - cp[1].y) - cy;
    ay = cp[3].y - cp[0].y - cy - by;
 
    /*計算t位置的點值*/
 
    tSquared = t * t;
    tCubed = tSquared * t;
 
    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
 
    return result;}
 /* ComputeBezier 以控制點 cp 所產生的曲線點,填入 Point2D 結構數組。 
    調用方必須分配足夠的空間以供輸出,<sizeof(Point2D) numberOfPoints>>
*/
 void ComputeBezier( Point2D* cp, int numberOfPoints, Point2D* curve ){
    float   dt;
    int    i;
 
    dt = 1.0 / ( numberOfPoints - 1 );
 
    for( i = 0; i < numberOfPoints; i++)
        curve[i] = PointOnCubicBezier( cp, i*dt );}

在歷史上,研究貝塞爾曲線的人最初是按照已知曲線參數方程來確定四個點的思路設計出這種矢量曲線繪制法。

如果已知一條曲線的參數方程,系數都已知,並且兩個方程裏都含有一個參數t,它的值介於0、1之間,表現形式如下所示:
x(t) = ax * t ^ 3 + bx * t ^ 2 + cx * t + x0
y(t) = ay * t ^ 3 + by * t ^ 2 + cy * t + y0

由於這條曲線的起點(x0,y0)是已知的,我們可以用以下的公式來求得剩余三個點的坐標:
x1 = x0 + cx / 3
x2 = x1 + ( cx + bx ) / 3
x3 = x0 + cx + bx + ax

y1 = y0 + cy / 3
y2 = y1 + ( cy + by ) / 3
y3 = y0 + cy + by + ay

仔細觀察一下就知道了,無論方程的已知和所求是什麽,總是有六個未知數,並且我們總能找到六個等式(記住(x0,y0)總是已知的),也就是說,上面的方法是完全可逆的,因此我們可以根據四個已知點坐標來反求曲線參數公式的系數。稍微一變換就得到了下面這組公式:
cx = 3 * ( x1 - x0 )
bx = 3 * ( x2 - x1 ) - cx
ax = x3 - x0 - cx - bx

cy = 3 * ( y1 - y0 )
by = 3 * ( y2 - y1 ) - cy
ay = y3 - y0 - cy - by

所以說,對於坐標任意的四個已知點,你總能創建一條貝塞爾曲線,這樣在邏輯判斷及使用中就可以創建自己所需的貝塞爾曲線效果。

貝塞爾曲線