貝塞爾曲線學(xué)習(xí)筆記

前言

近段時間我在工作中實現(xiàn)了一個動畫功能,其中涉及到動畫元素要按一定的軌跡在屏幕上移動,運(yùn)動軌跡的生成我使用了Path.cubicTo方法來實現(xiàn)的,這個方法其實是生成了一條有兩個控制點(diǎn)的貝塞爾曲線。借此機(jī)會我再收集了一些資料,想系統(tǒng)地學(xué)習(xí)一下貝塞爾曲線相關(guān)的知識。

簡介

貝塞爾曲線(Bézier curve)又被稱為貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線,它的數(shù)學(xué)基礎(chǔ)是伯恩斯坦多項式(Bernstein polynomial,since 1912),1959年法國數(shù)學(xué)家Paul de Casteljau提出了數(shù)值穩(wěn)定的de Casteljau算法,開始貝塞爾曲線的圖形化應(yīng)用研究,而貝塞爾曲線的名稱來源于一位就職于雷諾的法國工程師Pierre Bézier,他在1962年開始對貝塞爾曲線做了廣泛的宣傳,他使用這種只需要很少的控制點(diǎn)就能生成復(fù)雜平滑曲線的方法來進(jìn)行汽車車體的工業(yè)設(shè)計。

貝塞爾曲線因為它控制簡便卻具有極強(qiáng)的描述能力,迅速在工業(yè)設(shè)計和計算機(jī)圖形學(xué)等相關(guān)領(lǐng)域得到了廣泛應(yīng)用。比如在矢量繪圖中,貝塞爾曲線用來給需要無限制地縮放的平滑曲線定模,許多繪圖軟件都提供了繪制貝塞爾曲線的功能。貝塞爾曲線還用于動畫時間控制以實現(xiàn)美觀逼真的緩動效果,還用于機(jī)器人轉(zhuǎn)動手臂等方面的設(shè)計。

de Casteljau算法原理

在向量AB上選擇一個點(diǎn)C,使得C分向量AB為u:1-u(即|AC|:|AB|=u)。給定點(diǎn)A、B的坐標(biāo)以及u(u∈[0,1])的值,點(diǎn)C的坐標(biāo)則為C=A+(B-A)*u=(1-u)*A+u*B。

de Casteljau算法基本原理

貝塞爾曲線原理

利用de Casteljau算法可以計算貝塞爾曲線上的點(diǎn)C(u),u∈[0,1]。因此,通過給定一組u的值,即可算出貝塞爾曲線上的坐標(biāo)序列,從而繪制出貝塞爾曲線。

為了計算n階貝塞爾曲線上的點(diǎn)C(u),u∈[0,1],首先將控制點(diǎn)連接形成一條折線00-01-02······0(n-1)-0n,利用de Casteljau算法,計算出折線中每條線段0j-0(j+1)上的一個點(diǎn)1j,使得點(diǎn)1j分該線段的比為u:1-u,然后在折線10-11-12-······-1(n-1)上遞歸調(diào)用該算法,以此類推。最終求得一個點(diǎn)n0,已證明點(diǎn)n0一定是曲線上的點(diǎn)。

de Casteljau算法的幾何表達(dá)

上圖中u=0.4,這從幾何形狀上形象地說明了de Casteljau算法的過程,可以將上述直觀的幾何描述表達(dá)為算術(shù)方法,如下圖所示:

de Casteljau算法的算術(shù)表達(dá)圖示

首先將所有的控制點(diǎn)排成一列,如上圖最左列,每一對相鄰的控制點(diǎn)之間畫出兩個箭頭,分別指向右下方和右上方,在兩個箭頭交匯的位置記下一個新的點(diǎn)。比如控制點(diǎn)ij和i(j+1)生成新的控制點(diǎn)(i+1)j。指向右下方的箭頭表示乘以(1-u),指向右上方的箭頭表示乘以u。

將上述過程表達(dá)為下面的算法:

Input:arrayP[0:n] ofn+1 points and real numberuin [0,1]

Output:point on curve,C(u)

Working:point arrayQ[0:n]

fori:= 0 to n do

? ? Q[i] :=P[i]; // save input

fork:= 1 to n do

? ? fori:= 0ton - kdo

? ? ? ? Q[i] := (1 -u)Q[i] +uQ[i+ 1];

returnQ[0];

這個算法還可以被遞歸地表達(dá),上述點(diǎn)列還有其他有趣的性質(zhì),詳細(xì)描述請參考論文Finding a Point on a Bézier Curve: De Casteljau's Algorithm。

貝塞爾曲線展示

一階貝塞爾曲線

一階貝塞爾曲線動畫,t∈[0,1]

給定點(diǎn)P0和P1,一階貝塞爾曲線就是這兩點(diǎn)間的一條直線段,對應(yīng)公式:

一階貝塞爾曲線的一般方程

二階貝塞爾曲線

二階貝塞爾曲線動畫,t∈[0,1]

給定點(diǎn)P0、P1和P2,二階貝塞爾曲線是由下述方程產(chǎn)生的軌跡

二階貝塞爾曲線的直接方程

這個方程可以被描述為由兩段獨(dú)立的一階貝塞爾曲線再按de Casteljau算法合成的,分別是由 P0 至 P1 的連續(xù)點(diǎn) Q0描述一條線段,由 P1 至 P2 的連續(xù)點(diǎn) Q1描述另一條線段,最后由 Q0 至 Q1 的連續(xù)點(diǎn) B(t)描述了貝塞爾曲線。整理上述公式變成:

二階貝塞爾曲線的一般方程

三階貝塞爾曲線


三階貝塞爾曲線動畫,t∈[0,1]

二維平面或者更高維度的空間中的4個點(diǎn)P0、P1、P2和P3可以定義一條三階的貝塞爾曲線,這條曲線從P0點(diǎn)開始向P1點(diǎn)方向運(yùn)動,最后從來自P2點(diǎn)的方向運(yùn)動到達(dá)P3點(diǎn)。一般點(diǎn)P1和P2不會在曲線上,它們用來控制曲線運(yùn)動的方向;點(diǎn)P0與P1間的距離將會影響曲線在轉(zhuǎn)向P2之前向P1點(diǎn)方向運(yùn)動的遠(yuǎn)近和快慢。按照二階貝塞爾曲線方程可以表達(dá)為一階的形式,三階貝塞爾曲線也可以由兩個二階貝塞爾曲線組合來線性地表達(dá):

三階貝塞爾曲線的線性表達(dá)式

將方程遞歸帶入整理得到:

三階貝塞爾曲線的一般方程

更一般地,n階貝塞爾曲線的一般方程為:

n階貝塞爾曲線的一般表達(dá)式

例如,n=5時,即5階貝塞爾曲線的方程為:

5階貝塞爾曲線的一般方程

貝塞爾曲線應(yīng)用

Android SDK中提供的API

在android.graphics包中的Path類提供了幾個可以繪制貝塞爾曲線的API,常用的就是lineTo、quadTo和cubicTo三個方法,分別可以繪制一、二、三階的貝塞爾曲線,一階沒什么可說的,就是通常的畫直線,傳入的參數(shù)就是目標(biāo)點(diǎn)坐標(biāo)。下面分別是quadTo和cubicTo方法的接口說明:

Path類的quadTo方法說明
Path類的cubicTo方法說明

自定義貝塞爾工具

在實際項目中我自己寫了一個貝塞爾估值器類,核心方法如下:

自定義貝塞爾估值器


后記

我第一次寫這樣長篇的技術(shù)博客,慚愧??!想以此加深自己的理解,也方便以后迅速查閱相關(guān)的資料。寫博客真的是一個深入學(xué)習(xí)的好方法,讓我不再流于解決問題的表面,通過查找資料可以透過直接的技術(shù)方案發(fā)現(xiàn)方案背后的邏輯和原理。理解了最本質(zhì)的東西,其他的都是可以舉一反三、觸類旁通的方法變幻。加油,少年!~


Thanks To:

貝塞爾曲線掃盲

貝塞爾曲線初探

Wikipedia:Bézier curve

Finding a Point on a Bézier Curve: De Casteljau's Algorithm

BezierDemo源碼解析-實現(xiàn)qq消息氣泡拖拽消失的效果

基于貝塞爾曲線的Android動畫差值器

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容