简化高阶贝塞尔曲线

5
我有一个控制点数组,代表了一个贝塞尔曲线。这可能是一个五阶或一百阶的贝塞尔曲线,或者在它们之间的任何阶数。我正在寻找一种将该贝塞尔曲线简化为多个三次贝塞尔曲线的方法。下面的插图展示了如何将十度曲线简化为三度曲线,但我想进一步简化它,将其简化为几个三次贝塞尔曲线以达到更好的逼近效果。

http://snag.gy/aHPjc.jpg

代码示例将非常有帮助。

一般而言:分段贝塞尔曲线不过是B样条曲线的一种。 - Christian
2个回答

5
如mohsenmadi所指出的那样:一般情况下,这不是一件您可以做到而不需要提出自己的错误指标的事情。另一个想法是“将此曲线近似为较低阶曲线的序列”,这样我们就可以得到看起来更好、并且不需要真正的错误度量的东西。这有点像将曲线“平坦化”为直线,只不过我们要使用立方贝塞尔段,这样可以得到漂亮的曲线,并且在现代图形库方面保持所有内容的可操作性。
然后我们可以做的是:通过定期间隔采样曲线,然后将这些点通过Catmull-Rom算法进行运行,将“100阶曲线”分成多个立方贝塞尔的序列。这个过程非常简单:
1. 挑选一些等距的t值,如0、0.2、0.4、0.6、0.8和1,然后 2. 创建点集tvalues.map(t => getCoordinate(curve, t))。然后, 3. 构建虚拟起点和终点:通过从点1开始沿其切线向后移动,并通过从n开始按其切线向前移动来形成点0,形成点n+1。我们这样做,因为: 4. 从虚拟点0开始构建多段Catmull-Rom,并以虚拟点n+1结束。
让我们通过图片来演示一下。我们从一个11阶贝塞尔曲线开始: enter image description here 然后,让我们按照规则对其进行定期采样: enter image description here 我们创造一个第0个点和第n+1个点: enter image description here 然后,我们运行Catmull-Rom过程:
i = 0
e = points.length-4
curves = []
do {
  crset = points.subset(i, 4)
  curves.push(formCRCurve(crset))
} while(i++<e)
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)

我们可以看到为什么需要这些虚拟点:在给定四个点的情况下,我们可以使用一些来自第一和第四个点的切线信息,从第二个点到第三个点形成一个Catmull-Rom曲线。

当然,我们实际上想要的是贝塞尔曲线,而不是Catmull-Rom曲线,但是因为它们是相同类型的曲线,所以我们可以在两者之间自由转换,因此:

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,可以写成等效的Bezier曲线,该曲线使用起始/控制1 /控制2 /结束坐标p2p2 + (p3-p1)/6p3-(p4-p2)/6p3


1
两个问题:**(1)** 第二个 formCurve 函数中的 d_startd_end 是做什么的?我应该用第二个函数替换第一个函数,还是应该以某种方式同时使用它们? (2) 我尝试实现这个,只使用了你最后一段提供的信息,但只有当我使用 p2 + (p3 - p1)/6p3 - (p4 - p2)/6 时才得到合理的结果。请注意,我交换了 +-。我犯了错误还是你犯了错误? - mhelvens
好的,有很好的观点!让我更新答案。第二个函数替换了第一个函数(第一个函数产生Catmull-Rom曲线,第二个函数基于Catmull-Rom曲线产生Bezier曲线)。是的,我完全意外地使用了+/-符号。 - Mike 'Pomax' Kamermans

1
首先,你必须知道没有逼近更低次数的曲线可以完全代替你!你注定会引入误差。问题在于:如何逼近使得原始曲线和结果曲线在视觉上相似?
假设你的原始曲线的次数为n。首先,对其进行细分。你可以无限次地对曲线进行细分而不引入任何误差。在这里,每个细分的次数仍为n,但几何复杂性和曲率率降低了很多。第二,降低每个细分的次数,现在它们是简单的形状,没有高曲率会引入逼近误差。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接