简化高阶贝塞尔曲线

Simplify high-order Bezier curve

我有一组代表贝塞尔曲线的控制点。它可以是五阶或 100 阶贝塞尔曲线,或介于两者之间的任何曲线。我正在寻找一种方法将该贝塞尔曲线简化为多条三次贝塞尔曲线。下图展示了十度曲线如何简化为三度曲线,但我想更进一步,将其简化为几条三次贝塞尔曲线以实现更好的近似。

代码示例会很有帮助。

首先,您必须知道没有近似的低阶曲线可以让您公正!你一定会引入无法逃避的错误。那么问题是:如何近似使得原始曲线和结果曲线在视觉上相似?

假设您的原始曲线的阶数为 n。首先,subdivide it. You can subdivide a curve as many times as you want without introducing any errors. Here, the degree of each subdivisions is still n, but the geometric complexity and rate of curvature are reduced considerably. Second, you reduce the degree 每个细分现在是一个简单的形状,没有高曲率,不会引入近似误差。

正如 mohsenmadi 已经指出的那样:一般来说,如果不提出自己的错误指标,就无法做到这一点。另一个想法是 "well let's just approximate this curve as a sequence of lower order curves",这样我们就可以得到看起来更好的东西,而且实际上不需要错误指标。这有点像 "flattening" 曲线到线,除了我们将使用立方贝塞尔线段代替线,这提供了漂亮的曲线,同时保持一切 "tractable" 与现代图形库一样很关心。

然后我们可以做的是:通过定期对曲线进行采样,然后 运行 通过 Catmull-Rom 算法将这些点合并,将“100 阶曲线”拆分为一系列三次贝塞尔曲线。程序很简单:

  1. t 选择一些规则间隔的值,例如 0、0.2、0.4、0.6、0.8 和 1,然后
  2. 创建点集 tvalues.map(t => getCoordinate(curve, t))。那么,
  3. 构建虚拟起点和终点:从点 1 开始并沿其切线向后移动形成点 0,从 [= 开始形成点 n+1 17=] 并跟随它的切线。我们这样做是因为:
  4. 构建 poly-Catmull-Rom,从虚拟点 0 开始,在虚拟点 n+1 结束。

让我们在图片中做到这一点。让我们从 11 阶贝塞尔曲线开始:

然后让我们定期对其进行采样:

我们发明第 0 点和第 n+1 点:

然后我们 运行 Catmull-Rom 程序:

i = 0
e = points.length-4
curves = []
do {
  crset = points.subset(i, 4)
  curves.push(formCRCurve(crset))
} while(i++<e)

formCRCurve 有什么作用?好问题:

formCRCurve(points: p1, p2, p3, p4):
  d_start = vector(p2.x - p1.x, p2.y - p1.y)
  d_end = vector(p4.x - p3.x, p4.y - p3.y)
  return Curve(p2, d_start, d_end, p3)

所以我们明白了为什么我们需要这些虚拟点:给定四个点,我们可以使用从点 1 和点 4 获得的切线信息从点 2 到点 3 形成一条 Catmull-Rom 曲线。

当然,我们实际上想要贝塞尔曲线,而不是 Catmull-Rom 曲线,但是因为它们是相同的 "kind" 曲线,我们可以 freely convert between the two,所以:

i = 0
e = points.length-4
bcurves = []
do {
  pointset = points.subset(i, 4)
  bcurves.push(formBezierCurve(pointset))
} while(i++<e)

formBezierCurve(points: p1, p2, p3, p4):
  return bezier(
    p2,
    p2 + (p3 - p1)/6
    p3 - (p4 - p2)/6
    p3
  )

因此,基于点 {p1,p2,p3,p4} 的 Catmull-Rom 曲线通过 通过 p2p3,可以写成使用 start/control1/control2/end 坐标 p2p2 + (p3 - p1)/6p3 - (p4 - p2)/6p3.

的等效贝塞尔曲线