如何解决分段贝塞尔曲线是否通过垂直线测试?
考虑具有 N 个段的分段三次贝塞尔曲线,根据 4N 个控制点定义。如何确定这条曲线是否通过了垂直线测试?也就是说:是否存在点 x,y1,y2 使得 y1!=y2 并且 (x,y1) 和 (x,y2) 都位于曲线上?此外,如果这些点存在,返回点 x,y2 的值会很好但不是必需的。
原则上,您可以只在大量点上明确评估曲线,但在我的应用程序中,曲线可能有大量段,因此速度非常慢。因此,我正在寻找一种仅在控制点上运行的算法,而不依赖于在大量点上明确评估曲线。
解决方法
根据定义,闭合曲线会使您的测试失败,所以让我们看一下开放曲线:对于无法通过垂直线测试的曲线,分段三次 polyBezier 中的至少一个线段需要沿 x 轴“反转方向”,这意味着它的 x 分量需要在包含区间 [0,1] 内 have extrema。
例如,这条曲线没有(右侧显示 x 的 component function,全局极值为红色,拐点为紫色):
(另请注意,我们只绘制了 [0,1] 区间,但如果我们扩展它,那些全局极值实际上不会位于 t=0
和 t=1
。这实际上非常重要,我们将在下面看到原因)
这条曲线也没有(但只有只是):
但这条曲线确实:
这个也是。事实上两次:
就像曲线“刚过它的尖端”一样:
当我们夸大它时更容易看出:
这意味着我们需要找到一阶导数,找出它在哪里为零,然后确保(因为贝塞尔曲线可能有尖点)该导数的符号在那个点(或点,因为可以有两个)翻转.
事实证明,导数是 trivially not-even-really-computed,所以对于每个段,我们有:
w = [x1,x2,x3,x4]
Bx(t) = w[0] * (1-t)³ + 3 * w[1] * t(1-t)² + w[2] * t²(1-t) + w[3] * t³
// bezier form of the derivative:
v = [
3 * (w[1] - w[0]),3 * (w[2] - w[1]),3 * (w[3] - w[2]),]
Bx'(t) = v[0] * (1-t)² + 2 * v[1] * t(1-t) + v[2] * t²
我们可以简单地重写为多项式形式:
a = v[0] - 2*v[1] + v[2]
b = 2 * (v[1] - v[0])
c = v[0]
Bx'(t) = a * t² + b * t + c
所以我们找到了它的根,这就是应用 quadratic formula 的问题,它给了我们 0、1 或 2 个根。
if (a == 0) there are no roots
denominator = 2 * a
discriminant = b * b - 2 * denominator * c
if (discriminant < 0) there are no (real) roots
d = sqrt(discriminant)
t1 = -(b + d) / denominator
if (0 ≤ t1 ≤ 1) then t1 is a valid root
t2 = (d - b) / denominator
if (0 ≤ t2 ≤ 1) then t2 is a valid root
如果没有(实数)根,则该段不会导致曲线无法通过您的垂直线测试,我们将继续进行下一段并重复,直到我们发现失败,或者我们已经要测试的段用完了。
如果是 1 或 2 个根,我们检查 Bx'(t-ε)
和 Bx'(t+ε)
的符号对于一些非常小的 ε 值是否不同(因为我们想确保我们不会得出上述结论带尖头的曲线未通过测试:它的导数为零,但它“继续沿相同方向”穿过该根而不是翻转方向)。如果是,则该线段是使您的曲线无法通过垂直线测试的线段之一。
另外,请注意,即使根在 0 或 1 处,我们也在进行测试:分段曲线可能会“跨段”弯曲,我们可以利用这样一个事实:我们可以评估 Bx'(t) 用于 t = -ε
或 t = 1+ε
以查看我们是否翻转方向,即使我们从未在 t=0
之前或 {{1} 之后绘制曲线}}。
将解决方案留在这里以供参考。不是特别优雅,但可以完成工作。假设曲线从左到右参数化。关键观察是曲线在两点与垂线相交当且仅当存在 x 分量的导数 x'(t) 严格为负的点。对于三次贝塞尔曲线,导数是二次多项式 x'(t)=at^2+bt+c。所以我们只需要检查这个二次方在区间 0
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。