如何可靠地确定两条平面贝塞尔曲线是否相交?“可靠”是指测试仅在曲线相交时回答“是”,而在曲线不相交时回答“否”。我不需要知道在哪里找到交集的参数。我还想在实现中使用浮点数。
我在StackOverflow上找到了几个答案,这些答案使用曲线的边界框进行测试:这不是我想要的,因为即使曲线不相交,此类测试也可能报告相交。
到目前为止,我找到的最接近的东西是Sederberg和Meyers 的“ 边界楔 ”,但“仅”区分最多一个和两个或更多的交叉,而我想知道是否最多为零和一个或多个交叉路口。
如何可靠地确定两条平面贝塞尔曲线是否相交?“可靠”是指测试仅在曲线相交时回答“是”,而在曲线不相交时回答“否”。我不需要知道在哪里找到交集的参数。我还想在实现中使用浮点数。
我在StackOverflow上找到了几个答案,这些答案使用曲线的边界框进行测试:这不是我想要的,因为即使曲线不相交,此类测试也可能报告相交。
到目前为止,我找到的最接近的东西是Sederberg和Meyers 的“ 边界楔 ”,但“仅”区分最多一个和两个或更多的交叉,而我想知道是否最多为零和一个或多个交叉路口。
Answers:
解决问题的另一种方法是定义一个函数,该函数给出两条曲线上的点之间的距离,作为曲线参数的函数。然后尝试找到此函数的全局最小值。如果曲线相交,最小值将为零;否则,最小值将为零。否则最小值将是一些正距离。
明确地说,给定由定义的一对2D曲线,将距离平方定义为
对于三次曲线,函数是两个变量的六次多项式。然后,您可以应用数值优化技术,例如单纯形法或共轭梯度下降法。不幸的是,该函数可以具有多个局部最小值(不是凸的),因此优化并不容易。多项式可能有更专业的优化方法,但这对我来说不是专业领域。
[免责声明:我认为以下内容应该有效,但我自己尚未对其进行编码]
我想不出产生“是/否”答案的“平凡”方法,但是下面的方法将是解决该问题的合理方法。
假设曲线分别为A(s)和B(t),分别具有控制点{ A0,A1..An }和{ B0,.. Bm }。
在我看来,鉴于我们要确定其相交或不相交的一对2D贝塞尔曲线,有六种情况需要考虑:
我们可以“平凡”地确定它们不相交的情况。
它们相交有限次数的情况,我们可以“轻松地”确定它们至少相交了一次(但我们实际上并不关心这些相交的位置)
贝塞尔曲线之一是简并的,即一个点(如果所有控制点都相同,则将发生)。我们可以假设我们已经处理了两个都是点的情况。
例如,闭合一条或多条曲线。A0 == An。为了简化生活,我们将细分这些曲线并重新开始。
有无限多个交点,因为每个交点都是“父”贝塞尔曲线的子集,并且它们重叠。
我们不确定上述情况,需要进一步调查
目前,我们将忽略3和4,但稍后再返回。
正如您在问题中暗示的那样,如果A和B的控制点的各自边界框不相交,则曲线就不能相交。显然,这是一个快速的拒绝测试,但过于保守。您可能知道,对于贝塞尔曲线,其控制点的凸包在曲线上形成(更紧)边界。因此,我们可以使用分离轴技术来确定A和B的外壳是否不相交。(例如,如Wikipedia中所示:)
如果案例1测试失败,则可以检查相交的“平凡”存在。现在可能有更好的方法来执行此操作,但是以下相对便宜的方法出现在我身上:
仅考虑曲线A:
我们知道曲线开始于,结束于,并将位于凸包内。为简单起见,让我们计算线段的方向,并计算任一侧的边界(即,取剩余控制点的点积与的垂直线的)。甲Ñ ¯ 甲0 甲Ñ ¯ 甲0 甲Ñ
如果我们发现和是B的外面相对的界限和该和上A的边界的外侧,然后通过贝济耶的连续性,必须有至少一个相交。A n B 0 B m
如果我们不能立即显示上述两种情况,则将每个Beziers分成两个“一半”,即。这是相对简单的(留给读者练习),但是对于二次贝塞尔曲线而言却特别琐碎:
递归比较4个组合:。显然,如果全部通过情况1,则不存在交叉点。如果任何一个失败,则继续使用该减少的子集进行其余测试。
这在这里变得更加乏味。
如果“案例3”通过“案例1”测试,在我看来,您需要解决一个实际的交集。假设有一个简单的过程可以将贝塞尔曲线的N个控制点A(s)映射到贝塞尔曲线的N-1个点A'(s),代表它们的一阶导数(但要注意相对罕见的所谓的“退化”情况,即一阶导数确实为零),则可以使用牛顿迭代(在一维上)来找到潜在的解。
还要注意,由于A'(s)的控制点在导数值上是有界的,因此有可能尽早消除某些情况。
情况5似乎相对不太可能,所以也许只有在经过几次递归后没有确凿的证据时,才可以对曲线B尝试A的每个端点,反之亦然。这只会提供相交的证明,而不会提供不相交的证明。