贝塞尔曲线

贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。

在数学的数值分析领域中,贝塞尔曲线是电脑图形学中相当重要的参数曲线。


📐 数学公式

可以使用数学公式来描述贝塞尔曲线。
正如我们所看到的——实际上不需要知道,大多数人只是通过鼠标移动点来绘制曲线。 但如果你喜欢数学——就在这里。
给定控制点 Pi 的坐标:第一个控制点的坐标为 P1 = (x1, y1),第二个:P2 = (x2, y2),依此类推,曲线坐标由依赖于参数的方程来描述。 t 是步长,范围 [0,1]2 个控制点曲线的公式:
P = (1-t)P1 + t • P2

3 个控制点曲线的公式:
P = (1−t)² • P1 + 2(1−t)t • P2 + t² • P3

4 个控制点曲线的公式:
P = (1−t)³ • P1 + 3(1−t)² • t • P2 + 3(1−t)t² • P3 + t³ • P4


这些是向量方程。 换句话说,我们可以用x和y代替P来得到对应的坐标。
例如,3 点曲线由计算如下的点 (x,y) 形成:

x = (1−t)² • x1 + 2(1−t)t • x2 + t² • x3
y = (1−t)² • y1 + 2(1−t)t • y2 + t² • y3

📌 JavaScript

参考代码:index.js


/**
 * 贝塞尔曲线点的坐标计算
 * @param {Number} t   - 步长
 * @param {Object} p0  - 点的 x 和 y 坐标
 * @param {Object} p1  - 点的 x 和 y 坐标
 * @param {Object} p2  - 点的 x 和 y 坐标
 * @param {Object} p3  - 点的 x 和 y 坐标
 * @returns {Object} 返回经过计算后的点的坐标
 */
export function bezier(t, p0, p1, p2, p3) {
    const cX = 3 * (p1.x - p0.x),
          bX = 3 * (p2.x - p1.x) - cX,
          aX = p3.x - p0.x - cX - bX;

    const cY = 3 * (p1.y - p0.y),
          bY = 3 * (p2.y - p1.y) - cY,
          aY = p3.y - p0.y - cY - bY;

    const x = (aX * Math.pow(t, 3)) + (bX * Math.pow(t, 2)) + (cX * t) + p0.x;
    const y = (aY * Math.pow(t, 3)) + (bY * Math.pow(t, 2)) + (cY * t) + p0.y;

    return { x: x, y: y };
}

测试:test.js

import { bezier } from './index';


/**
 * canvas画布上返回一条贝塞尔曲线
 */
function draw() {

    /* step 指定了贝塞尔曲线分为 100断(步长) */
    const step = 0.01,
        p0 = { x: 10, y: 10 },
        p1 = { x: 50, y: 100 },
        p2 = { x: 150, y: 200 },
        p3 = { x: 200, y: 75 },
        ctx = document.createElement('canvas').getContext('2d');

    ctx.width = 500;
    ctx.height = 500;
    document.body.appendChild(ctx.canvas);

    ctx.moveTo(p0.x, p0.y);
    for (let i = 0; i < 1; i += step) {
        const p = bezier(i, p0, p1, p2, p3);
        ctx.lineTo(p.x, p.y);
    }

    ctx.stroke();
}
draw();