05- Bézier曲线的应用
文章目录
本文属于 “NURBS学习笔记” 专栏,更多文章可以点击↓↓↓
NURBS学习笔记专栏
Bézier曲线已经贯穿至我们使用数字产品的方方面面,尤其是设计方面,本文举几个例子。
1. Bézier曲线与字体
字体设计作为平面设计中的一个重要艺术门类,在国内的关注度还需要提高。实际上这是一个美学与数学充分结合的学科,非常有趣。本文谈及的字体是 TrueType 字体,关于该字体格式的描述可以参考:
Apple - TrueType Reference Manual
otfcc - 一款解析OpenType字体向json格式解析和反向重构的工具
TrueType 字体的完整描述比较复杂。简单地讲,TrueType 使用二次贝塞尔样条以及直线描绘了字的轮廓,比起使用点阵,TrueType 字体可以无限放大而不会失真,这也是其名称的由来。我们可以使用 otfcc 的 otfccdump 工具,将选择的 TrueType 字体转换为 json 格式。例如我将 Windows 系统里的 consola.ttf 字体转换为 json 格式。在 json 文件的 “glyf” 键里就记录了各个字符的贝塞尔曲线的控制点的描述。
我们将某个字符的 “contours” 键值保存下来,可以看到一系列的控制点。我选了大写字母"J",并在 fontforge 里交互地观察这些点。如下图所示。从字母"J"的右上角开始,顺时针旋转,依次有22个点。
在 otfcc 导出的结果里,每个点除了有坐标信息,还有一个表示点是否在轮廓线上的标识,如上图所示,所有的红色点标识为"on",即在曲线上,蓝色点表示不在曲线上,是二次Bézier曲线的控制点,我们称之为“off”点。
TrueType的标准定义:每两个“on”点之间插入一个直线段,连续的“off”点连同首末两个“on”点构成一段连续的二次Bézier曲线。所以对于上面的字母“J”,我们知道它由10段构成,分别是。
- 直线段:P1->P2
- 二次Bézier曲线:P2->P3->P4->P5->P6->P7
- 二次Bézier曲线:P7->P8->P9->P10->P11->P12
- 直线段:P12->P13
- 二次Bézier曲线:P13->P14->P15->P16
- 二次Bézier曲线:P16->P17->P18->P19
- 直线段:P19->P20
- 直线段:P20->P21
- 直线段:P21->P22
- 直线段:P22->P1
1.1 连续2次Bézier曲线
前文所述,我们知道了一个 2 次 Bézier 曲线需要 3 个控制点,如果有
m
m
m 段 2 次 Bézier 曲线,其首尾依次保持
G
1
G_1
G1 连续呢?假设
P
i
,
0
,
P
i
,
1
,
P
i
,
2
,
0
≤
i
<
m
P_{i,0},P_{i,1},P_{i,2},0 \le i < m
Pi,0,Pi,1,Pi,2,0≤i<m 是第
i
i
i 段2次Bézier曲线的3个控制点。则根据
G
1
G_1
G1 连续的要求有:
{
P
0
,
2
=
P
1
,
0
⋮
P
m
−
2
,
2
=
P
m
−
1
,
0
P
0
,
2
−
P
0
,
1
=
P
1
,
1
−
P
1
,
0
⋮
P
m
−
2
,
2
−
P
m
−
2
,
1
=
P
m
−
1
,
1
−
P
m
−
1
,
0
\left\{ \begin{matrix} \begin{aligned} \mathbf{P}_{0,2}&=\mathbf{P}_{1,0} \\ \vdots \\ \mathbf{P}_{m-2,2}&=\mathbf{P}_{m-1,0} \\ \mathbf{P}_{0,2}-\mathbf{P}_{0,1} &= \mathbf{P}_{1,1}-\mathbf{P}_{1,0} \\ \vdots \\ \mathbf{P}_{m-2,2}-\mathbf{P}_{m-2,1} &= \mathbf{P}_{m-1,1}-\mathbf{P}_{m-1,0} \\ \end{aligned} \end{matrix} \right.
⎩
⎨
⎧P0,2⋮Pm−2,2P0,2−P0,1⋮Pm−2,2−Pm−2,1=P1,0=Pm−1,0=P1,1−P1,0=Pm−1,1−Pm−1,0
上式一共 2 m − 2 2m-2 2m−2 个条件,而 m m m 段 2 次 Bézier 曲线一共 3 m 3m 3m 个条件,所以我们需要给出 m + 2 m+2 m+2 个条件。可以将每一段Bézier曲线中间的控制点给出即 P i , 1 , 0 ≤ i < m P_{i,1},0 \le i < m Pi,1,0≤i<m ,一共 m m m 个,另再补充第 0 0 0 段的第1个控制点 P 0 , 0 P_{0,0} P0,0 和第 m − 1 m-1 m−1 段的第3个控制点 P m − 1 , 2 P_{m-1,2} Pm−1,2 即可。
对于我们给出的例子,表示字母 “J” 右下部分的 2 次 Bézier 曲线:P2->P3->P4->P5->P6->P7,虽然只给出了6个点,但我们可以推知,其由 4 段 2 次 Bézier 曲线组成。并且我们可以推知每一段的 3 个控制点。下图将 4 段 Bézier 曲线的各个控制点以及每一段曲线都以对应颜色区分标出。
段数 | P 0 \mathbf{P}_{0} P0 | P 1 \mathbf{P}_{1} P1 | P 2 \mathbf{P}_{2} P2 |
---|---|---|---|
0 \color{red}0 0 | P 0 , 0 = P 2 \color{red}\mathbf{P}_{0,0}\color{black}=\mathbf{P}_2 P0,0=P2 | P 0 , 1 = P 3 \color{red}\mathbf{P}_{0,1}\color{black}=\mathbf{P}_3 P0,1=P3 | P 0 , 2 = ( P 0 , 1 + P 1 , 1 ) / 2 = ( P 3 + P 4 ) / 2 \color{red}\mathbf{P}_{0,2}\color{black}=(\color{red}\mathbf{P}_{0,1}\color{black}+\color{blue}\mathbf{P}_{1,1}\color{black})/2=(\mathbf{P}_3+\mathbf{P}_4)/2 P0,2=(P0,1+P1,1)/2=(P3+P4)/2 |
1 \color{blue}1 1 | P 1 , 0 = ( P 0 , 1 + P 1 , 1 ) / 2 = ( P 3 + P 4 ) / 2 \color{blue}\mathbf{P}_{1,0}\color{black}=(\color{red}\mathbf{P}_{0,1}\color{black}+\color{blue}\mathbf{P}_{1,1}\color{black})/2=(\mathbf{P}_3+\mathbf{P}_4)/2 P1,0=(P0,1+P1,1)/2=(P3+P4)/2 | P 1 , 1 = P 4 \color{blue}\mathbf{P}_{1,1}\color{black}=\mathbf{P}_4 P1,1=P4 | P 1 , 2 = ( P 1 , 1 + P 2 , 1 ) / 2 = ( P 4 + P 5 ) / 2 \color{blue}\mathbf{P}_{1,2}\color{black}=(\color{blue}\mathbf{P}_{1,1}\color{black}+\color{green}\mathbf{P}_{2,1}\color{black})/2=(\mathbf{P}_4+\mathbf{P}_5)/2 P1,2=(P1,1+P2,1)/2=(P4+P5)/2 |
2 \color{green}2 2 | P 2 , 0 = ( P 1 , 1 + P 2 , 1 ) / 2 = ( P 4 + P 5 ) / 2 \color{green}\mathbf{P}_{2,0}\color{black}=(\color{blue}\mathbf{P}_{1,1}\color{black}+\color{green}\mathbf{P}_{2,1}\color{black})/2=(\mathbf{P}_4+\mathbf{P}_5)/2 P2,0=(P1,1+P2,1)/2=(P4+P5)/2 | P 2 , 1 = P 5 \color{green}\mathbf{P}_{2,1}\color{black}=\mathbf{P}_5 P2,1=P5 | P 2 , 2 = ( P 2 , 1 + P 3 , 1 ) / 2 = ( P 5 + P 6 ) / 2 \color{green}\mathbf{P}_{2,2}\color{black}=(\color{green}\mathbf{P}_{2,1}\color{black}+\color{purple}\mathbf{P}_{3,1}\color{black})/2=(\mathbf{P}_5+\mathbf{P}_6)/2 P2,2=(P2,1+P3,1)/2=(P5+P6)/2 |
3 \color{purple}3 3 | P 3 , 0 = ( P 2 , 1 + P 3 , 1 ) / 2 = ( P 5 + P 6 ) / 2 \color{purple}\mathbf{P}_{3,0}\color{black}=(\color{green}\mathbf{P}_{2,1}\color{black}+\color{purple}\mathbf{P}_{3,1}\color{black})/2=(\mathbf{P}_5+\mathbf{P}_6)/2 P3,0=(P2,1+P3,1)/2=(P5+P6)/2 | P 3 , 1 = P 6 \color{purple}\mathbf{P}_{3,1}\color{black}=\mathbf{P}_6 P3,1=P6 | P 3 , 2 = P 7 \color{purple}\mathbf{P}_{3,2}\color{black}=\mathbf{P}_7 P3,2=P7 |
至此,我们就能将 TrueType 所描绘的字体轮廓绘制出来了。
2. Bézier曲线与 Adobe 全家桶
如果你是一名设计师,那你应该是 Adobe 全家桶的重度使用者,无论是在 Photoshop、Illustrator 还是 Premiere Pro,都有一款钢笔工具,使用钢笔工具可以在平面上勾画出直线或者曲线段,作为路径或者是封闭的图形。你也可以使用这个工具 The Bézier Game 交互感受钢笔工具的魅力。
虽然 Adobe 的钢笔工具在表示图形时使用了"锚点"、“手柄"的概念,但我们很容易看出来,实际上对于钢笔绘制出来的一段 Bézier 曲线弧,其"锚点”、“手柄"端点共同构成了该 Bézier 曲线弧的控制点。下图左侧即为 Illustrator 中绘制的一段路径线,其实际上由 5 段曲线组成,而且都是 3 次 Bézier 曲线。是的,你没听错,这些曲线段都是 3 次的。右图将所谓的"锚点”、"手柄"端点都标识为某一段 Bézier 弧的控制点了。图中 2 个蓝色的曲线段很好理解,每一段的 4 个控制点明显可知。可为什么说红色的直线段和两个绿色的曲线段也是 3 次 Bézier 曲线,它们的 4 个控制点在哪里?明明绿色曲线仅有 3 个明显的控制点,曲线的形态也很符合 2 次 Bézier 曲线,但它怎么就是 3 次的呢。后文我们可以将这些数据导出为 SVG 格式进行仔细探究。
实际上,钢笔工具的路径线所用的 Bézier 曲线就是 3 次的,如我们上文所讲,3 次及以下的 Bézier 曲线其控制点的调整符合设计者的预期,如 3 次 Bézier 曲线的控制点为
P
0
,
P
1
,
P
2
,
P
3
\mathbf{P}_0,\mathbf{P}_1,\mathbf{P}_2,\mathbf{P}_3
P0,P1,P2,P3 ,改变
P
0
,
P
3
\mathbf{P}_0,\mathbf{P}_3
P0,P3 则曲线的首末点也跟着改变,改变
P
1
,
P
2
\mathbf{P}_1,\mathbf{P}_2
P1,P2 则曲线的首末切矢也跟着分别改变,并且整个曲线图形控制在
P
0
,
P
1
,
P
2
,
P
3
\mathbf{P}_0,\mathbf{P}_1,\mathbf{P}_2,\mathbf{P}_3
P0,P1,P2,P3 的凸包内。更高次的曲线的不靠近端点处的控制点几何意义就不是很明确了;更高次的曲线也意味着曲线拥有更高的自由度,也更难控制。
2.1 导出钢笔路径到SVG
Illustrator 内使用钢笔绘制的 Bézier 曲线段的控制点不太好捕获,我们可以将 Illustrator 文件导出为同是矢量图表示的 SVG 格式。下面两个链接是关于 SVG 格式的描述。实际上我们仅关注其中对于轮廓线描述的部分。
Joshua Bragg - Cubic Bezier Curves with SVG Paths
我们根据 SVG 格式的描述文档,将 Illustrator 转出的 SVG 格式描述的几何坐标手动处理成我们容易理解的形式,具体坐标如下所示,坐标已标注在上图中。
Line
0.43,194.81
120.16,0.63
Cubic Bézier 1
……
Cubic Bézier 2
……
Cubic Bézier 3
240.89,380.31
376.60,331.62
323.75,490.31
323.75,490.31
Cubic Bézier 4
323.75,490.31
323.75,490.31
-6.74,376.86
204.02,543.67
可以看到,SVG 文件一共描述了 5 个几何图形: 1 条直线和 4 条 3 3 3 次 Bézier 曲线,对于 Cubic Bézier 3 和 4,就对应了图中两个绿色的曲线段。再次观察 SVG 格式的 Cubic Bézier 3 和 4,其与普通的 3 3 3 次 Bézier 曲线最大的不同就在于它的后两个控制点或者前两个控制点都是重复的。我们可以具体考察下这类端控制点重复的曲线的特点。对于某个 3 3 3 次 Bézier 曲线,我们有
C ( u ) = P 0 B 0 , 3 ( u ) + P 1 B 1 , 3 ( u ) + P 2 B 2 , 3 ( u ) + P 3 B 3 , 3 ( u ) = ( 1 − u ) 3 P 0 + 3 u ( 1 − u ) 2 P 1 + 3 u 2 ( 1 − u ) P 2 + u 3 P 2 = [ ( 1 − u ) 3 P 0 + 2 u ( 1 − u ) 2 P 1 + u 2 ( 1 − u ) P 2 ] + [ u ( 1 − u ) 2 P 1 + 2 u 2 ( 1 − u ) P 2 + u 3 P 3 ] = ( 1 − u ) [ ( 1 − u ) 2 P 0 + 2 u ( 1 − u ) P 1 + u 2 P 2 ] + u [ ( 1 − u ) 2 P 1 + 2 u ( 1 − u ) P 2 + u 2 P 3 ] \begin{aligned} \mathbf{C}(u) &= \mathbf{P}_0B_{0,3}(u) + \mathbf{P}_1B_{1,3}(u) + \mathbf{P}_2B_{2,3}(u) + \mathbf{P}_3B_{3,3}(u) \\ &= (1-u)^3\mathbf{P}_0 + 3u(1-u)^2\mathbf{P}_1 + 3u^2(1-u)\mathbf{P}_2 + u^3\mathbf{P}_2 \\ &= \left[(1-u)^3\mathbf{P}_0 + 2u(1-u)^2\mathbf{P}_1 + u^2(1-u)\mathbf{P}_2 \right] + \left[ u(1-u)^2\mathbf{P}_1 + 2u^2(1-u)\mathbf{P}_2 + u^3\mathbf{P}_3 \right] \\ &= (1-u)\left[\color{red}(1-u)^2\mathbf{P}_0 + 2u(1-u)\mathbf{P}_1 + u^2\mathbf{P}_2 \color{black}\right] + u\left[\color{red} (1-u)^2\mathbf{P}_1 + 2u(1-u)\mathbf{P}_2 + u^2\mathbf{P}_3 \color{black}\right] \\ \end{aligned} C(u)=P0B0,3(u)+P1B1,3(u)+P2B2,3(u)+P3B3,3(u)=(1−u)3P0+3u(1−u)2P1+3u2(1−u)P2+u3P2=[(1−u)3P0+2u(1−u)2P1+u2(1−u)P2]+[u(1−u)2P1+2u2(1−u)P2+u3P3]=(1−u)[(1−u)2P0+2u(1−u)P1+u2P2]+u[(1−u)2P1+2u(1−u)P2+u2P3]
可以看到,上述红色高亮的部分就是 P 0 , P 1 , P 2 {\mathbf{P}_0,\mathbf{P}_1,\mathbf{P}_2} P0,P1,P2 和 P 1 , P 2 , P 3 {\mathbf{P}_1,\mathbf{P}_2,\mathbf{P}_3} P1,P2,P3 形成的 2 2 2 次 Bézier 曲线,上面这个写法让我们有这样一个认识: 3 3 3 次 Bézier 曲线是两个 2 2 2 次 Bézier 曲线在对应位置的线性组合,组合权重 1 − u 1-u 1−u 和 u u u 也是随着 u u u 变化的;同样的,对于 2 2 2 次 Bézier 曲线,我们也可以看做两个 1 1 1 次 Bézier 曲线的线性组合。这个递推的思想可以让我们把任何一个高次的 Bézier 曲线都看做是多个 1 1 1 次 Bézier 曲线的多层线性混合。这个观点我们先初步感受,暂按下不表。
我们仍回到 “
3
3
3 次 Bézier 曲线是两个
2
2
2 次 Bézier 曲线在对应位置的线性组合” 这个讨论上。取一组一般的控制点演示这个过程如下。
那么当
3
3
3 次 Bézier 曲线的 4 个控制点
P
0
,
P
1
,
P
2
,
P
3
{\mathbf{P}_0,\mathbf{P}_1,\mathbf{P}_2, \mathbf{P}_3}
P0,P1,P2,P3 中发生了首、尾控制点重合意味着什么呢?比如对于 SVG 文件中的 Cubic Bézier 3,
P
2
=
P
3
\mathbf{P}_2=\mathbf{P}_3
P2=P3 ,此时用于混合的
P
1
,
P
2
,
P
3
{\mathbf{P}_1,\mathbf{P}_2,\mathbf{P}_3}
P1,P2,P3 形成的
2
2
2 次 Bézier 曲线就退化成直线了,此时有
C
(
u
)
=
(
1
−
u
)
[
(
1
−
u
)
2
P
0
+
2
u
(
1
−
u
)
P
1
+
u
2
P
2
]
+
u
[
(
1
−
u
)
2
P
1
+
2
u
(
1
−
u
)
P
2
+
u
2
P
2
]
\begin{aligned} \mathbf{C}(u) &= (1-u)\left[\color{red}(1-u)^2\mathbf{P}_0 + 2u(1-u)\mathbf{P}_1 + u^2\mathbf{P}_2 \color{black}\right] + u\left[\color{red} (1-u)^2\mathbf{P}_1 + 2u(1-u)\mathbf{P}_2 + u^2\mathbf{P}_2 \color{black}\right] \\ \end{aligned}
C(u)=(1−u)[(1−u)2P0+2u(1−u)P1+u2P2]+u[(1−u)2P1+2u(1−u)P2+u2P2]
第二项中的 ( 1 − u ) 2 P 1 + 2 u ( 1 − u ) P 2 + u 2 P 2 (1-u)^2\mathbf{P}_1 + 2u(1-u)\mathbf{P}_2 + u^2\mathbf{P}_2 (1−u)2P1+2u(1−u)P2+u2P2 表示了从 P 1 \mathbf{P}_1 P1 到 P 2 \mathbf{P}_2 P2 的直线,但要注意这根直线并不是随参数线性变化的。我们绘制出此时的混合情况,如下所示。
我们仍将表示 3 3 3 次 Bézier 曲线首尾速度、加速度方向的关键矢量进行标注,有下图。曲线在 P 0 \mathbf{P}_0 P0 处的一些性质我就不再赘述了,现在看 P 3 \mathbf{P}_3 P3 处,在该处速度方向已经为 0 \mathbf{0} 0 了(该点是一个奇异点),但我们仍能够计算出此处的加速度方向 ( P 3 − P 2 ) − ( P 2 − P 1 ) = P 1 − P 2 (\mathbf{P}_3-\mathbf{P}_2)-(\mathbf{P}_2-\mathbf{P}_1)=\mathbf{P}_1-\mathbf{P}_2 (P3−P2)−(P2−P1)=P1−P2 。这样的一个 3 3 3 次 Bézier 与 P 0 , P 1 , P 2 {\mathbf{P}_0,\mathbf{P}_1,\mathbf{P}_2} P0,P1,P2 形成的 2 2 2 次 Bézier 曲线形态非常相似,但要注意,两者并不相等,下图也用浅蓝色线标出了这个 2 2 2 次 Bézier 曲线。
至此,我们就能够理解 Illustrator 中绘制的那两根绿色的曲线为什么说它们是 3 3 3 次的了,并且也知道它们消失的那个控制点其实就是将首或者尾部重复 1 次得到的。
顺着这个思路,如果 P 0 = P 1 \mathbf{P}_0=\mathbf{P}_1 P0=P1 ,并且 P 2 = P 3 \mathbf{P}_2=\mathbf{P}_3 P2=P3 ,那我们就能够得到一根直线了,也就是 Illustrator 中绘制的那根红色的直线。
为什么要大费周章地将直线表示为 3 3 3 次 Bézier 曲线?与其这么问,倒不如说,Adobe 全家桶中的“钢笔”工具就是仅支持绘制 3 3 3 次 Bézier 曲线的工具,只不过,其根据每一段曲线的控制点的重复次数、相邻两段控制点是否共线等特性建立了一套面向用户的“钢笔”工具,并有“尖点锚点”、“平滑锚点”、“手柄”等概念,也支持直线的绘制。
当你绘制了两个尖点,则表示了一条直线,当你拖动某个尖点,将“手柄”拉出来,即减少了某个端点处的重复度,如果你把另一个尖点的“手柄”也拉伸出来,就是一个普通的 3 3 3 次 Bézier 曲线了。
2.2 3次够不够
我们再想另一个问题:如何用 3 3 3 次 Bézier曲线描绘一个圆弧?你可以在 Photoshop、Illustrator 里先绘制一个圆,试试钢笔工具能不能绘制出一条完全覆盖圆弧的曲线?答案是:理论上是不能的(幂基曲线不能,Bézier 曲线等价于一条幂基曲线,后文会证明这个事),但是作为一款表达不用很精确的设计类软件,你可以用很多段 Bézier 曲线去逼近。这就让我们思考这样一个问题:钢笔工具仅支持 3 次 Bézier 曲线够不够?可以从这几个方面给出答案:3 次可控性很好;平面设计类软件不需要很高的精确度;可以用连续多段去表示更复杂的轮廓。
钢笔工具这个例子也让我们体会到数学工具照进现实应用时要保持一定的克制。为用户提供更易用的简单工具比单纯地所谓支持更高级但无用的功能来得更难。
3. Bézier曲线与PowerPoint
微软的 PowerPoint 实际上也给我们提供了一套 Bézier 曲线的创建工具,通过 “插入”->“形状”->“线条”->“曲线” 命令,我们就能在屏幕上连续做点,创建一条连续的曲线。实际上这也是一组 3 3 3 次Bézier 曲线。在创建完曲线后,通过 “编辑顶点” 命令,可以拖动调整每个点,也可以拖动每个点上的手柄,类似 Adobe 软件中的“钢笔”工具。
对于 PowerPoint 中的“曲线”命令,假如我们连续点击了 6 个屏幕上的点(下图中 P 0 , 0 , P 1 , 0 , P 2 , 0 , P 3 , 0 , P 4 , 0 , P 4 , 3 \mathbf{P}_{0,0},\mathbf{P}_{1,0},\mathbf{P}_{2,0},\mathbf{P}_{3,0},\mathbf{P}_{4,0},\mathbf{P}_{4,3} P0,0,P1,0,P2,0,P3,0,P4,0,P4,3),那么我们将能够创建出 5 段 3 3 3 次Bézier 曲线。显然,输入的 6 个点的信息是不足以完全确定这 5 段 3 3 3 次Bézier 曲线的,那就意味着软件尽可能从我们的输入补充了其他控制点的信息,我们可以简单探究 PowerPoint 是如何通过已有输入确定整个控制多边形的,我将结合下图把探究结果进行描述。
-
在屏幕上连续做两个点,实际为 P 0 , 0 \mathbf{P}_{0,0} P0,0 和 P 0 , 3 \mathbf{P}_{0,3} P0,3 ,此时绘制出的是一条直线(实际仍为 3 3 3 次 Bézier 曲线),其实已经有点
P 0 , 1 = ( 1 − 1 3 ) P 0 , 1 + 1 3 P 0 , 3 P 0 , 2 = ( 1 − 2 3 ) P 0 , 1 + 2 3 P 0 , 3 \mathbf{P}_{0,1}=(1-\frac{1}{3})\mathbf{P}_{0,1}+\frac{1}{3}\mathbf{P}_{0,3} \\ \mathbf{P}_{0,2}=(1-\frac{2}{3})\mathbf{P}_{0,1}+\frac{2}{3}\mathbf{P}_{0,3} P0,1=(1−31)P0,1+31P0,3P0,2=(1−32)P0,1+32P0,3 -
再在屏幕上确定一点,则为 P 1 , 3 \mathbf{P}_{1,3} P1,3 ,此时,有两个 3 3 3 次 Bézier 曲线,最开始创建的第一条直线的各控制点将做如下调整:
P 0 , 2 = P 0 , 3 + 1 6 ( P 0 , 0 − P 1 , 3 ) P 0 , 1 = 1 2 P 0 , 0 + 1 2 P 0 , 2 \mathbf{P}_{0,2}=\mathbf{P}_{0,3}+\frac{1}{6}(\mathbf{P}_{0,0}-\mathbf{P}_{1,3}) \\ \mathbf{P}_{0,1}=\frac{1}{2}\mathbf{P}_{0,0}+\frac{1}{2}\mathbf{P}_{0,2} P0,2=P0,3+61(P0,0−P1,3)P0,1=21P0,0+21P0,2第一条线各控制点在后续的创建中都保持不动了,同时对于第二条线,也能够确定:
P 1 , 1 = P 1 , 0 + 1 6 ( P 1 , 3 − P 0 , 0 ) P 1 , 2 = 1 2 P 1 , 1 + 1 2 P 1 , 3 \mathbf{P}_{1,1}=\mathbf{P}_{1,0}+\frac{1}{6}(\mathbf{P}_{1,3}-\mathbf{P}_{0,0}) \\ \mathbf{P}_{1,2}=\frac{1}{2}\mathbf{P}_{1,1}+\frac{1}{2}\mathbf{P}_{1,3} P1,1=P1,0+61(P1,3−P0,0)P1,2=21P1,1+21P1,3对于第二条线,如果再有新的 P 2 , 3 \mathbf{P}_{2,3} P2,3 被创建,则其将根据 P 2 , 3 , P 1 , 0 \mathbf{P}_{2,3},\mathbf{P}_{1,0} P2,3,P1,0 进行修改,否则就保持现状。
-
新的点的加入同上述步骤2。
尽管我们没有 PowerPoint 的源码,但通过对其结果的分析也能够看出其在根据用户有限的输入给定初始图形时,还是尽可能从输入中补充了缺失控制点。上述过程中的各种系数 1 6 , 1 3 , 1 2 \frac{1}{6},\frac{1}{3},\frac{1}{2} 61,31,21 以及计算过程中蕴含的平行信息(比如图中 P 1 , 2 , P 2 , 1 \mathbf{P}_{1,2},\mathbf{P}_{2,1} P1,2,P2,1 与 P 2 , 3 , P 1 , 0 \mathbf{P}_{2,3},\mathbf{P}_{1,0} P2,3,P1,0 )其实表达了这样一层意思:让曲线的变化趋势尽可能贴合用户的有限输入。
由此也可见 PowerPoint 的曲线工具与 Adobe 的钢笔工具的差异:两者都是用来绘制曲线的,底层其实都表达为 3 3 3 次 Bézier 曲线;但前者让用户先交互输入有限的点,给一个相对比较好的结果,然后再提供工具进行调整,后者允许用户在交互输入时就将各控制点确定好。
由此我们可以进一步思考软件的交互设计,同样的 3 3 3 次 Bézier 曲线创建工具,用不同的交互逻辑给演绎出来了。良好的人机交互,快速捕获用户设计意图也是我们作为工具类软件开发者应该多考虑的事情,尤其是 CAx 类软件,除了在底层算法下功夫,交互层也需要谨慎考虑和设计。