使用二階貝塞爾曲線畫愛心

簡介

上一篇這一篇讓你徹底搞懂貝塞爾曲線的原理中,我們介紹了貝塞爾曲線的原理。這一篇我們先用二階貝塞爾曲線來做一個應用 —— 繪製愛心。首先回顧一下二階貝塞爾曲線。

如上圖所示,經過推導得出的曲線上的點 P 的計算公式如下:


愛心繪製控制點

首先我們來看愛心使用二階貝塞爾曲線如何實現。如下圖所示,愛心可以分爲4段曲線,分別是 P0-P1,P1-P2,P2-P3和 P3-P0之間的四段曲線,其中 P0-P1和 P1-P2是對稱的,P2-P3和 P3-P0也是對稱的。



有了這個基礎,我們就可以在各段曲線的中間增加一個控制點,形成二階貝塞爾曲線所需的三個控制點,如下圖所示。



當然,爲了讓愛心好看,這些點需要仔細調整,尤其是P1-P2和 P2-P3的兩段曲線斜接處需要過渡得平滑。

代碼實現

代碼實現的關鍵是調節點位參數和封裝一個獲取二階貝塞爾曲線的函數方便重複調用,然後就是設置一個 t 變量,通過循環等間隔生成曲線的一些列點就可以繪製出曲線了。下面是根據三個控制點獲取二階貝塞爾曲線在 t 時刻點的位置的方法。

Offset get2OrderBezierPoint(Offset p1, Offset p2, Offset p3, double t) {
  var x = (1 - t) * (1 - t) * p1.dx + 2 * t * (1 - t) * p2.dx + t * t * p3.dx;
  var y = (1 - t) * (1 - t) * p1.dy + 2 * t * (1 - t) * p2.dy + t * t * p3.dy;

  return Offset(x, y);
}

繪製P0-P1的曲線代碼如下所示,每段曲線使用了100個點。這裏注意,由於使用小數循環可能因爲浮點數的偏差導致循環點數少,因此這裏的 t 先乘了100倍進行循環,然後再除以100來避免這種情況的出現。

var p0 = Offset(offset1x, center1y);
var p1 = Offset(size.width / 4 - offset1x, side1y);
var p2 = Offset(size.width / 2, center1y);
var path1 = Path();
path1.moveTo(p0.dx, p0.dy);
for (var t = 1; t <= 100; t += 1) {
  var curvePoint = get2OrderBezierPoint(p0, p1, p2, t / 100.0);
  path1.lineTo(curvePoint.dx, curvePoint.dy);
}
canvas.drawPath(path1, paint);

其他曲線段的代碼相同,只是控制點不同而已,實現的效果圖下,爲了方便查看控制點位置和曲線的關係,我們將控制點也畫了出來。完整代碼已經上傳至:CustomPaint 繪製相關代碼

總結

本篇介紹了二階貝塞爾曲線的實際應用,實際繪製過程中我們發現曲線拼接處(途中的綠色點)的控制點很難調整到過渡平滑,導致調整繪製效果需要花費很多時間調整控制點位置,這種情況實際需要使用三階貝塞爾曲線來解決。下一篇我們來用三階貝塞爾曲線重新繪製愛心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章