# 贝塞尔曲线

贝塞尔曲线用于计算机图形绘制形状,CSS 动画和许多其他地方。

它们其实非常简单,值得学习一次并且在矢量图形和高级动画的世界里非常受用。

# 一阶贝塞尔曲线

一阶贝塞尔曲线就是线段

q=(1t)p0+tp1q = (1-t)p_0 + tp_1

// a 10, 50 // b 310, 100
ctx.moveTo(10, 50);
ctx.lineTo(310, 100);
ctx.stroke();
// a 10, 150 // b 310, 200
oneBezier(10, 150, 310, 200);
function oneBezier(x0, y0, x1, y1) {
  for (let i = 0; i < 100; i++) {
    let t = i / 100;
    // q = (1-t)p_0+ tp_1
    let a = (1 - t) * x0 + t * x1;
    let b = (1 - t) * y0 + t * y1;
    ctx.fillRect(a, b, 1, 1);
  }
}

# 二阶贝塞尔曲线

(三个点) 一个起始点 一个控制点 一个终点

quadraticCurveTo(cp1x, cp1y, x, y)

两个基准向量的二次函数拟合路径

q=(1t)2p0+2t(1t)p1+t2p2q = (1-t)^2p_0+2t(1-t)p_1+t^2p_2

// a 50,50 // b 100,100 // b 300,50
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(100, 100, 300, 50);
ctx.stroke();
// a 50,150 // b 100,200 // b 300,150
twoBezier(50, 150, 100, 200, 300, 150);
function twoBezier(x0, y0, x1, y1, x2, y2) {
  for (let i = 0; i < 100; i++) {
    let t = i / 100;
    // q = (1-t)^2p_0+2t(1-t)p_1+t^2p_2
    let a = Math.pow(1 - t, 2) * x0 + 2 * t * (1 - t) * x1 + t * t * x2;
    let b = Math.pow(1 - t, 2) * y0 + 2 * t * (1 - t) * y1 + t * t * y2;
    ctx.fillRect(a, b, 1, 1);
  }
}

# 三阶贝塞尔曲线

(四个点) 一个起始点 两个控制点 一个终点

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

三个基准向量的三次函数拟合路径

q=(1t)3p0+3t(1t)2p1+3t2(1t)p2+t3p3q = (1-t)^3p_0+3t(1-t)^2p_1+3t^2(1-t)p_2+t^3p_3

// a 50,0 // b 100,50 // c 200, 120 // d 300,75
ctx.moveTo(50, 0);
ctx.bezierCurveTo(100, 50, 200, 120, 300, 75);
ctx.stroke();
// a 50,120 // b 100,170 // c 200,240 // d 300,195
threeBezier(50, 100, 100, 170, 200, 240, 300, 195);
function threeBezier(x0, y0, x1, y1, x2, y2, x3, y3) {
  for (let i = 0; i < 100; i++) {
    const t = i / 100;
    // q = (1-t)^3p_0+3t(1-t)^2p_1+3t^2(1-t)p_2+t^3p_3
    const x =
      Math.pow(1 - t, 3) * x0 +
      3 * t * Math.pow(1 - t, 2) * x1 +
      3 * Math.pow(t, 2) * (1 - t) * x2 +
      Math.pow(t, 3) * x3;
    const y =
      Math.pow(1 - t, 3) * y0 +
      3 * t * Math.pow(1 - t, 2) * y1 +
      3 * Math.pow(t, 2) * (1 - t) * y2 +
      Math.pow(t, 3) * y3;
    ctx.fillRect(x, y, 1, 1);
  }
}

实际渲染效果

# 参考资料

贝塞尔曲线参数方程推导 - 哔哩哔哩 (opens new window)

贝塞尔曲线 - 现代 JavaScript 教程 (opens new window)