css贝塞尔曲线 多个点_了解贝塞尔曲线的数学和Python实现示例

贝塞尔曲线在计算机图形学中被大量使用,通常可以产生平滑的曲线。如果您曾经使用过Photoshop,则可能会发现名为“锚点”的工具,您可以在其中放置锚点并用它们绘制一些曲线,这些也是贝塞尔曲线。如果您使用了基于矢量的图形SVG,这些也会使用贝塞尔曲线。让我们看看它是如何工作的。

定义

给定n + 1 个点(P0,…,Pn)称为控制点,这些点定义的贝塞尔曲线定义为:

d1f7888adae5093209414856eb02e3dd.png

eq. 1

其中B(t)称为Bernstein多项式:

5d7e4a173baf82ddde688e1d97b81cee.png

eq. 2

你会注意到这个伯恩斯坦多项式看起来很像牛顿二项式公式中的第k项,也就是:

16d4fb2e94acbcd066ad05bf647631fd.png

eq. 3

事实上,伯恩斯坦多项式就是(t + (1 - t))^n = 1的展开式中的第k项。这就是为什么如果你把所有的Bi加到n,你会得到1。

二次贝塞尔曲线

二次贝塞尔曲线就是我们所说的有三个控制点的贝塞尔曲线,P(t)的阶数是2。让我们计算给定3个控制点的贝塞尔曲线,并探索一些我们可能会发现的特性!请记住,公式1适用于n+1个点,所以在我们的例子中n=2。

866c522bc3d8cf20024cc9fd89c73498.png

eq. 4

注意,P(t)返回的不是一个数字,而是曲线上的一个点。现在我们只需要选择三个控制点,然后在[0,1]范围内对曲线求值。我们可以在Python中很容易地做到这一点。

import numpy as npimport matplotlib.pyplot as pltP0, P1, P2 = np.array([[0, 0],[2, 4],[5, 3]])# define bezier curveP = lambda t: (1 - t)**2 * P0 + 2 * t * (1 - t) * P1 + t**2 * P2# evaluate the curve on [0, 1] sliced in 50 pointspoints = np.array([P(t) for t in np.linspace(0, 1, 50)])# get x and y coordinates of points separatelyx, y = points[:,0], points[:,1]# plotplt.plot(x, y, 'b-')plt.plot(*P0, 'r.')plt.plot(*P1, 'r.')plt.plot(*P2, 'r.')plt.show()
0cd7ab80d18051264cc4295f1546f9d9.png

您会注意到曲线从第一个控制点处开始,到最后一个控制点处结束。这个结果对任意数量的点都成立。由于t的取值范围是从0到1,我们可以通过求P(t)在t=0和t=1时的值来证明这一点。使用eq.1:

b22256dc727b894138dede5b985cdefe.png

eq. 5

44b6a9ce38406ef00b1cea14782c12b5.png

eq. 6

因为是从P0到P2,P1完全决定了曲线的形状。移动P1你可能会注意到:

ff5ac64d85930e1a5702598de4aaf015.png

贝塞尔曲线总是包含在控制点形成的多边形中。这个多边形因此被称为控制多边形,或者贝塞尔多边形。这个属性也适用于任意数量的控制点,这使得它们在使用软件时的操作非常直观。

f03c991bcaba283ee15a3cdd5aaa2cb3.png

控制多边形还具有以下特性:包含曲线的面积最小,称为凸包。

插补

贝塞尔曲线的一个有趣应用是绘制一条通过一组预定义点的平滑曲线。之所以有趣,是因为P(t)的公式产生点,并且不是y = f(x)的形式,因此一个x可以具有多个y。。例如,我们可以这样画:

bb4805e42faadbd3a98ff7102b11f872.png

下面是如何使用公式1为任意数量的控制点编写通用版本的Bezier曲线。

import numpy as npimport matplotlib.pyplot as pltfrom math import factorialdef comb(n, k):    return factorial(n) // (factorial(k) * factorial(n - k))def get_bezier_curve(points):    n = len(points) - 1    return lambda t: sum(        comb(n, i) * t**i * (1 - t)**(n - i) * points[i]        for i in range(n + 1)    )def evaluate_bezier(points, total):    bezier = get_bezier_curve(points)    new_points = np.array([bezier(t) for t in np.linspace(0, 1, total)])    return new_points[:,0], new_points[:,1]points = np.array([    [0, 0],    [-1, 3],    [4, 3],    [6, 0],    [7, 2.5]])x, y = points[:,0], points[:,1]bx, by = evaluate_bezier(points, 50)plt.plot(bx, by, 'b-')plt.plot(x, y, 'r.')plt.show()

运行该Python程序,显示如下图形:

33f27c8dada464cf2bc483c9750b500c.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值