贝塞尔曲线

2023/2/11

# 一次贝塞尔曲线

image.png

P 点随时间 t 在 P0 到 P1 两点之间的线段移动,t=0 时刻,P 点和 P0 重合,t=1 时刻 P 点和 P1 重合。最终推导得到 P 点的位置和 P0,P1 及 t 的关系是一个线性插值函数:

img

t=0 时 P 点坐标 = (1 - 0)P0 + 0P1 = P0

t=1 时 P 点坐标 = (1-1)P0 + 1P1 = P1

# 二次贝塞尔取曲线

二次贝塞尔曲线在线测试 (opens new window)

image.png

① 求出 A 点坐标(P0 点到 P1 点的一次贝塞尔曲线),A 点坐标 = (1-t)P0 + tP1

② 求出 B 点坐标(P1 点到 P2 点的一次贝塞尔曲线),B 点坐标 = (1-t)P1 + tP2

③ 求出 P 点坐标(A 点到 B 点的一次贝塞尔曲线),P 点坐标 = (1-t)A + tB

化简(1-t)A + tB = (1-t)[(1-t)P0+tP1] + t[(1-t)P1+tP2]

image-20230110104855220

# 三次贝塞尔曲线

image.png

第一步

① 求出 A 点坐标(P0 点到 P1 点的一次贝塞尔曲线),A 点坐标 = (1-t)P0 + tP1

② 求出 B 点坐标(P1 点到 P2 点的一次贝塞尔曲线),B 点坐标 = (1-t)P1 + tP2

③ 求出 C 点坐标(P2 点到 P3 点的一次贝塞尔曲线),B 点坐标 = (1-t)P2 + tP3

第二步

① 求出 D 点坐标(A 点到 B 点的一次贝塞尔曲线),D 点坐标 = (1-t)A + tB

② 求出 E 点坐标(B 点到 C 点的一次贝塞尔曲线),E 点坐标 = (1-t)B + tC

第三步

求出 P 点坐标(D 点到 E 点的一次贝塞尔曲线),P 点坐标 = (1-t)D + tE

# 求二次贝塞尔曲线上的点

image-20230110104855220

根据公式写出代码

var ctx = canvas.getContext('2d');
// 绘制一段二次贝塞尔曲线
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(200, 200, 350, 50);
// 绘制
ctx.stroke();

// P0 (50, 50),P1 (200, 200),P2 (350, 50)
const t = 0.3;

const x = (1 - t) * (1 - t) * 50 + 2 * t * (1 - t) * 200 + t * t * 350;
const y = (1 - t) * (1 - t) * 50 + 2 * t * (1 - t) * 200 + t * t * 50;
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
console.log(x, y);
ctx.fill();

image-20230110114037291

# 求 P1,P2

P0 起点坐标,P3 结束点坐标是已知的。

P1 的 Y 坐标和 P0 的 Y 坐标一致

P2 的 Y 坐标和 P3 的 Y 坐标一致

只需要求 P1 的 X 轴坐标和 P2 的 X 轴坐标。

P1 的 X 轴坐标和 P2 的 X 轴坐标一致,

image-20230110144320138

// 获取绘图上下文
var ctx = canvas.getContext('2d');

const x1 = 140.0302734375;
const y1 = 252.2;
const x2 = 226.0302734375;
const y2 = 289;
// 绘制一段三次贝塞尔曲线
ctx.moveTo(x1, y1);
ctx.bezierCurveTo(x1 + (x2 - x1) / 2, y1, x1 + (x2 - x1) / 2, y2, x2, y2);
// 绘制
ctx.stroke();

// P0
ctx.beginPath();
ctx.arc(x1, y1, 5, 0, 2 * Math.PI);
ctx.fill();

// P1 (XX,y1)
// 求出中间位置的差值 (x2-x1)/2
// 求X坐标值 x = x1 + (x2-x1)/2
// P1 (x,y1)
ctx.beginPath();
ctx.arc(x1 + (x2 - x1) / 2, y1, 5, 0, 2 * Math.PI);
ctx.fill();

// P2  (XX,y2)
// P2  (x1 + (x2 - x1) / 2,y2)
ctx.beginPath();
ctx.arc(x1 + (x2 - x1) / 2, y2, 5, 0, 2 * Math.PI);
ctx.fill();

// P3
ctx.beginPath();
ctx.arc(x2, y2, 5, 0, 2 * Math.PI);
ctx.fill();