連續bezier曲線的實現

2022-08-15 05:36:29 字數 2795 閱讀 2985

一系列的座標點,劃出一條平滑的曲線

基本上大部分繪圖工具都實現了3次bezier曲線,4個點確定一條3次bezier曲線。以html5中的canvas為例

let ctx = canvas.getcontex('2d');

ctx.moveto(20,20); // 曲線起點 fom

ctx.beziercurveto(20,100,200,100,200,20); // 分別為控制點 ctrl1,ctrl2, 終點 to

假定給定點的序列list,我們應該以list中的每個點為起點,其下乙個點next為終點繪製bezier曲線。

所以問題變成,如何確定這兩個點之間的兩個bezier控制點。

每一小段路徑from-to的bezier曲線並不是獨立的,其實收到了其前後兩個點的影響(prev,next)

我們在繪製每一段路徑的時候,引入其前點prev,和後點next共同計算當前bezier曲線的控制點ctrl1,ctrl2

如圖所示

繪製從from到to的bezier曲線,引入prev,next作參考點。

先依次連線4個點,記為線段l1,l2,l3,並求出其中點c1,c2,c3

連線中點,在c1c2上找一點f1, 使 l1:l2 = c1f1:f1c2。也就是 c1f1 = c1c2 * l1/(l1+l2)。我叫它線段比例法。看到有些演算法是求其垂足,或者中點,嘗試之後發現這個線段比例點繪製的曲線最流暢

將線段 f1c2 平移到 起始點 from上,另乙個端點就是所求的控制點ctrl1。

通常我們會設定乙個0-1的平滑度,乘以要平移的線段f1c2,然後得出最終的控制點。如果平滑度為0,那麼其控制點就變成from本身,我們所畫出來的圖形就是折線。

同理求出終點to的控制點ctrl2,計算過程注意平移位置關係。

我們留意到,當繪製第一段或者最後一段曲線時,沒有其前後參考點。這裡我的做法是如果該點沒有prev,prev等於自身;如果沒有next,令next等於to。僅供參考

ps. 這段**並不能直接執行,僅僅是幫助理解,其中大部分點用向量表示,並省略了向量的實現細節。(如果只是想ctrl+v的程式設計師,希望你從來沒看過這邊文章)

/**

* 獲取線段ab的k比例點,預設為1/2中點

* @param a

* @param b

* @param k

*/getcenterpoint: function(a, b, k=0.5) ,

/*** 獲取以c點為起點,以向量ab的平移的終點

* @param a

* @param b

* @param c

*/gettransionpoint: function(a, b, c) ,

/*** 計算bezier控制點

* @param from

* @param to

* @param prev

* @param next

*/getbeziercontrolpoint: function(from, to, prev, next) ,

換句話說,判斷滑鼠當前位置是否選中某一段bezier曲線

如果序列點list的x有序(或者y有序),(常見的例子是繪製圖表,x座標軸是有序排列的),那麼我們先依次對比所有的序列點x座標,確定其唯一所在區間

否則,我們要對每一小段bezier曲線進行判斷

判斷bezier上的一點,我們需要理解bezier曲線的原理和其函式。我們把這段曲線看作是一條路徑,假設從起點走到終點,需要花費10000個單位時間。對於每個單位之間t,我們可以用函式公式求得其座標:

我們拿這10000個座標點與我們的目標點比較,當其差值在乙個可接受的範圍內時,我們認為目標點就在我們的bezier曲線上。

應當注意的是,除了設定的誤差範圍外,分割的時間片(上面的10000)也會影響到最終結果。如果分割的時間片太少,導致間隙過大使得判斷失效。如果分割的時間片太多,又將嚴重提高計算所消耗的時間。

示例**

/**

* 判斷目標點p是否在bezier曲線(p1,p2,p3,p4)上

* @param p1

* @param p2

* @param p3

* @param p4

* @param p

* @param step

* @param range

* @return bezier曲線的選中點

*/isbezierpoint: function(p1, p2, p3, p4, p, step=0.001, range=0.5) ;}}

return null;

}

特別注意一點:假如我們的序列中某一點的位置發生改變,或者新增了乙個序列點,那麼其前後將有4個點(忽略端點)的控制點需要重新計算和更新,分別為:

以這個點為from的曲線(自身為起點)

以這個點為to的曲線(上乙個點為起點)

以這個點為prev的曲線(下乙個點為起點)

以這個點為next的曲線(上乙個點的上乙個點為起點)

for (let i=currentindex-2, j=0; j<4; i++,j++)

Bezier曲線簡單實現

關鍵的公式,此公式不能畫出勻速曲線 completedpercent為當前所想得到位置的百分比0.0f 1.0f 根據貝塞爾曲線函式,求得取得此時的x,y座標 pt.x 1 completedpercent 1 completedpercent x1 2 1 completedpercent com...

bezier曲線和bezier曲面

如果想理解貝塞爾曲面沒有對其數學基本的認識是很難的,如果你不願意讀這一部分或者你已經知道了關於她的數學知識你可以跳過。首先我會描述貝塞爾曲線再介紹生成貝塞爾曲面。奇怪的是,如果你用過乙個圖形程式,你就已經熟悉了貝塞爾曲線,也許你接觸的是另外的名稱。它們是畫曲線的最基本的方法,而且通常被表示成一系列點...

Bezier曲線的de Casteljau演算法證明

ezier曲線 又稱貝茲曲線或貝塞爾曲線 的定義和性質請看維基百科貝茲曲線。它的定義是 其中,e casteljau演算法揭示了bezier數學上很美的乙個性質,我八成相信是先有了這個性質,才有了上面的定義式,當然它們是等價的。首先來看維基百科中的三張圖 二次bezier曲線 三次bezier曲線 ...