可靠测试两条贝塞尔曲线的交点


9

如何可靠地确定两条平面贝塞尔曲线是否相交?“可靠”是指测试仅在曲线相交时回答“是”,而在曲线不相交时回答“否”。我不需要知道在哪里找到交集的参数。我还想在实现中使用浮点数。

我在StackOverflow上找到了几个答案,这些答案使用曲线的边界框进行测试:这不是我想要的,因为即使曲线不相交,此类测试也可能报告相交。

到目前为止,我找到的最接近的东西是Sederberg和Meyers 的“ 边界楔 ”,但“仅”区分最多一个和两个或更多的交叉,而我想知道是否最多为零和一个或多个交叉路口。


我不确定它是否如此存在,确定湿度或存在0-1或2或更大的可能性是微不足道的,但是该公式并不能真正确保无需实际检查即可确定其0或1。
joojaa

运行时要求是什么?一种应该能够产生相当准确的结果的解决方案是通过大量短的直线段来近似两条曲线,然后以成对的方式将它们相交。但这会花费大量时间和内存。
Dragonseel

@Dragonseel好吧,我真的很乐意提供任何解决方案,但是既然您问O(1)会很好。但是用线段近似曲线会导致与边界框重叠测试相同的问题……
Ecir Hana

有趣的问题。我认为没有简单的答案,但我想错了。您是否有Sederberg和Meyers论文的链接?
Daniel M Gessel

@DanielMGessel是的,请参见上面的编辑。
Ecir Hana

Answers:


6

解决问题的另一种方法是定义一个函数,该函数给出两条曲线上的点之间的距离,作为曲线参数的函数。然后尝试找到此函数的全局最小值。如果曲线相交,最小值将为零;否则,最小值将为零。否则最小值将是一些正距离。

明确地说,给定由定义的一对2D曲线,将距离平方定义为c1,c2:[0,1]R2

f(u,v):[0,1]2R0|c2(v)c1(u)|2

对于三次曲线,函数是两个变量的六次多项式。然后,您可以应用数值优化技术,例如单纯形法共轭梯度下降法。不幸的是,该函数可以具有多个局部最小值(不是凸的),因此优化并不容易。多项式可能有更专业的优化方法,但这对我来说不是专业领域。f


如果我们谈论三次贝塞尔曲线,为什么它是6阶多项式而不是3阶?和您链接的两种方法,它们是否仅能在找到解决方案,而不是整个?[0,1]2R2
Ecir Hana

1
@EcirHana这是6度,因为它是平方距离。(您可以对它进行平方根运算,但是它不再是多项式,并且在零处将变得不平滑。)请注意,是参数空间,而不是样条线所在的空间,即这些是带有端点的样条曲线。无论如何,这些方法都可以在,但是它们只能从初始猜测中“走下坡路”,并找到局部最小值。还需要更多检查整个参数区域并找到全局最小值。在那里限制参数空间可能会有所帮助。[0,1]R2
内森·里德

1
内森-漂亮的配方!我很生疏,但是:我认为您可以将每个贝塞尔曲线分成最多5个分段,通过或改变曲线的方向。作为的函数,最多可改变方向两次(导数的根),将曲线分为3个部分,其中2个可通过方向的改变再次划分。现在,您有了的不是直线段,而是“不要弯曲太多”的段。我认为,如果您按细分对选择的25个点开始搜索,可能总能找到全局最小值,但是我不太清楚如何证明(或反对)它。xyxciy
Daniel M Gessel '16

@Nathan:我曾经考虑过,但是花了很多时间编写代码以找到纹理压缩格式的最小值,这一切似乎都有些可怕。
西蒙F'2

5

[免责声明:我认为以下内容应该有效,但我自己尚未对其进行编码]

我想不出产生“是/否”答案的“平凡”方法,但是下面的方法将是解决该问题的合理方法。

假设曲线分别为A(s)B(t),分别具有控制点{ A0,A1..An }和{ B0,.. Bm }。

在我看来,鉴于我们要确定其相交或不相交的一对2D贝塞尔曲线,有六种情况需要考虑:

  1. 我们可以“平凡”地确定它们相交的情况。

  2. 它们相交有限次数的情况,我们可以“轻松地”确定它们至少相交了一次(但我们实际上并不关心这些相交的位置)

  3. 贝塞尔曲线之一是简并的,即一个点(如果所有控制点都相同,则将发生)。我们可以假设我们已经处理了两个都是点的情况。

  4. 例如,闭合一条或多条曲线。A0 == An。为了简化生活,我们将细分这些曲线并重新开始。

  5. 有无限多个交点,因为每个交点都是“父”贝塞尔曲线的子集,并且它们重叠。

  6. 我们不确定上述情况,需要进一步调查

目前,我们将忽略3和4,但稍后再返回。

情况1

正如您在问题中暗示的那样,如果AB的控制点的各自边界框不相交,则曲线就不能相交。显然,这是一个快速的拒绝测试,但过于保守。您可能知道,对于贝塞尔曲线,其控制点的凸包在曲线上形成(更紧)边界。因此,我们可以使用分离轴技术来确定AB的外壳是否不相交。(例如,如Wikipedia中所示:)

在此处输入图片说明

情况二

如果案例1测试失败,则可以检查相交的“平凡”存在。现在可能有更好的方法来执行此操作,但是以下相对便宜的方法出现在我身上:

仅考虑曲线A:

贝塞尔曲线的“脂肪线”边界

我们知道曲线开始于,结束于,并将位于凸包内。为简单起见,让我们计算线段的方向,并计算任一侧的边界(即,取剩余控制点的点积与的垂直线的)。Ñ ¯ 0 Ñ ¯ 0 ÑA0AnA0An¯A0An¯

如果我们对曲线B进行相同操作,则会得到以下(可能的)情况: 在此处输入图片说明

如果我们发现和是B的外面相对的界限该和上A的边界的外侧,然后通过贝济耶的连续性,必须有至少一个相交。A n B 0 B mA0AnB0Bm

案例6

如果我们不能立即显示上述两种情况,则将每个Beziers分成两个“一半”,即。这是相对简单的(留给读者练习),但是对于二次贝塞尔曲线而言特别琐碎A1,A2,B1,B2

递归比较4个组合:。显然,如果全部通过情况1,则不存在交叉点。如果任何一个失败,则继续使用该减少的子集进行其余测试。(A1,B1),(A2,B1)...(A2,B2)

情况3和5

这在这里变得更加乏味。

如果“案例3”通过“案例1”测试,在我看来,您需要解决一个实际的交集。假设有一个简单的过程可以将贝塞尔曲线的N个控制点A(s)映射到贝塞尔曲线的N-1个点A'(s),代表它们的一阶导数(但要注意相对罕见的所谓的“退化”情况,即一阶导数确实为零),则可以使用牛顿迭代(在一维上)来找到潜在的解。
还要注意,由于A'(s)的控制点在导数值上是有界的,因此有可能尽早消除某些情况。

情况5似乎相对不太可能,所以也许只有在经过几次递归后没有确凿的证据时,才可以对曲线B尝试A的每个端点,反之亦然。这只会提供相交的证明,而不会提供不相交的证明。


是的,但是我个人对Bm和/或B0都在A的最大和最小范围之内但不刺穿的情况更感兴趣,那么您需要细分,在最坏的情况下计算交点点。更好的方法是使用最小边界框(也称为粗线近似)。
joojaa

鉴于此,对于每个二进制细分,曲线与连接端点的线段之间的差会以合理的系数下降(并且,在我的头顶上方,我认为二次方可能是4倍),界限肯定会继续迅速收敛到“薄”丝带上。
西蒙F

是的,但最坏的情况是另一个贝塞尔曲线从另一个开始。
joojaa

您的意思是,例如,An == B0。您是否将其定义为交叉点?
西蒙F

不再像B0在曲线上的某处。甚至只是一个最小的穿越
joojaa
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.