Canvas 按路径画圆滑曲线 bezierCurveTo

我们先来看看一幅汽车模型的素描图

很精美是不是,不知道你有没有发现,很多线条都不是简单的直线或者弧线或者圆弧,而是下面这种

现实生活中我们很容易用画笔画出来,但是电脑上却没那么容易

如果在电脑上要画出这种流水线条,就要使用一种叫做 贝塞尔曲线 的画法

贝塞尔曲线

相信很多同学都知道 贝塞尔曲线 这个词,在很多地方都能经常看到

但并不是每位同学都清楚地知道,到底什么是 贝塞尔曲线,又是什么特点让它有这么高的知名度

贝塞尔曲线的数学基础是早在 1912 年就广为人知的伯恩斯坦多项式

但直到 1959 年,当时就职于雪铁龙的法国数学家 Paul de Casteljau 才开始对它进行图形化应用的尝试,并提出了一种数值稳定的 de Casteljau算法

然而贝塞尔曲线的得名,却是由于 1962 年另一位就职于雷诺的法国工程师 Pierre Bézier 的广泛宣传

它使用这种只需要很少的控制点就能够生成复杂平滑曲线的方法,来辅助汽车车体的工业设计

于是我们就能看到这张精美的汽车模型图

正是因为控制简便却具有极强的描述能力,贝塞尔曲线在工业设计领域迅速得到了广泛的应用

不仅如此,在计算机图形学领域,尤其是矢量图形学,贝塞尔曲线也占有重要的地位

今天我们最常见的一些矢量绘图软件,如 Flash、Illustrator、CorelDraw 等,无一例外都提供了绘制贝塞尔曲线的功能

甚至像 Photoshop 这样的位图编辑软件,也把贝塞尔曲线作为仅有的矢量绘制工具(钢笔工具)包含其中

正是因为控制简便却具有极强的描述能力,贝塞尔曲线在工业设计领域迅速得到了广泛的应用。不仅如此,在计算机图形学领域,尤其是矢量图形学,贝塞尔曲线也占有重要的地位。今天我们最常见的一些矢量绘图软件,如 Flash、Illustrator、CorelDraw 等,无一例外都提供了绘制贝塞尔曲线的功能。甚至像 Photoshop 这样的位图编辑软件,也把贝塞尔曲线作为仅有的矢量绘制工具(钢笔工具)包含其中

贝塞尔曲线在 web 开发领域同样占有一席之地。很多 JavaScript 动画,甚至 CSS3 新增的 transition-timing-function 属性,它的取值就可以设置为一个三次贝塞尔曲线方程

de Casteljau 算法

下面我们就通过例子来了解一下如何用 de Casteljau 算法绘制一条贝塞尔曲线

在平面内任选 3 个不共线的点,依次用线段连接

在第一条线段上任选一个点 D。计算该点到线段起点的距离 AD,与该线段总长 AB 的比例

根据上一步得到的比例,从第二条线段上找出对应的点 E,使得 AD/AB = BE/BC

连接这两点 DE

从新的线段 DE 上再次找出相同比例的点 F,使得 DF/DE = AD/AB = BE/BC

到这里,我们就确定了贝塞尔曲线上的一个点 F

接下来,让选取的点 D 在第一条线段上从起点 A 移动到终点 B,找出所有的贝塞尔曲线上的点 F

所有的点找出来之后,我们也得到了这条贝塞尔曲线

如果你实在想象不出这个过程,没关系,看动画

回过头来看这条贝塞尔曲线,为了确定曲线上的一个点,需要进行两轮取点的操作,因此我们称得到的贝塞尔曲线为二次曲线

这样记忆很直观,其实曲线的次数其实是由前面提到的伯恩斯坦多项式决定的

当控制点个数为 4 时,情况是怎样的?

步骤都是相同的,只不过每确定一个贝塞尔曲线上的点,要进行三轮取点操作 如图,AE/AB = BF/BC = CG/CD = EH/EF = FI/FG = HJ/HI,其中点 J 就是最终得到的贝塞尔曲线上的一个点

这样我们得到的是一条三次贝塞尔曲线

三次贝塞尔曲线

从上面的演示图中,我们可以看到三次贝塞尔曲线需要 4 个坐标点

  1. 两个起始和终点坐标,也是两个控制点
  2. 另外两个控制点坐标

Canvas bezierCurveTo() 方法

Canvas 提供了方法 bezierCurveTo() 用来绘制三次贝塞尔曲线

void ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

方法需要三个点。 第一、第二个点是控制点,第三个点是结束点

起始点是当前路径的最后一个点,绘制贝赛尔曲线前,可以通过调用 moveTo() 进行修改

参数 说明
cp1x 第一个控制点的 x 轴坐标
cp1y 第一个控制点的 y 轴坐标
cp2x 第二个控制点的 x 轴坐标
cp2y 第二个控制点的 y 轴坐标
x 结束点的 x 轴坐标
y 结束点的 y 轴坐标

注意

bezierCurveTo() 方法绘制出来的是虚拟路径,需要使用 stroke() 实体化

范例

下面的代码以 (173,126) 和 (149,237) 作为其实和结束坐标,以 (117,87) 和 (86,260) 作为控制点绘制一个贝塞尔曲线

<!DOCTYPE html>
<meta charset="utf-8"> 
<canvas id="canvas-2" width="300" height="200">
</canvas>

<script>
var c   = document.getElementById("canvas-2");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#9013FE"
ctx.beginPath();
ctx.moveTo(173,126)
ctx.bezierCurveTo(117,87,86,260,149,237);
ctx.stroke();
</script>

运行结果如下

贝塞尔曲线用途

贝塞尔曲线除了可以用在设计中划出平滑的流线型曲线外,可以可以用于动画中制作平滑的动画效果

后面的章节中我们会学习如何将贝塞尔曲线应用在动画当中

参考文档

  1. 贝塞尔曲线扫盲
  2. Bézier Curve (de Casteljau algorithm)

Canvas 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.