如何计算一条直线和一个二次贝塞尔曲线之间的最近点?
有一篇来自INRIA的科学论文涉及这个问题:计算两条贝塞尔曲线之间的最小距离(PDF在此)。
1. 简单的不好的方法 - 通过迭代从第一条曲线的点开始,然后从第二条曲线的点开始,并获得最小值。 2. 确定曲线之间距离的数学函数,并计算该函数的极限,如:
|Fcur1(t)-Fcur2(t)| ->0
Fs是向量。
我认为我们可以计算其导数以确定极值并获取最近和最远的点。
我稍后会考虑这个问题,并发布完整的回复。
将问题用标准分析术语表述:您需要最小化一个量(距离),因此您需要为该量制定一个方程,并找到一阶导数为零的点。通过使用曲线的参数p
进行单参数化,该参数介于第一个点的0和最后一个点的1之间。
在直线情况下,方程相当简单:从样条曲线的方程中获取x/y坐标,并通过向量方程(与直线法线的数量积)计算到给定直线的距离。
在曲线情况下,解析解可能会变得非常复杂。您可能需要使用诸如Nelder-Mead之类的数值最小化技术,或者由于您有一个1D连续问题,可以使用简单的二分法。
我只想给你一些提示,针对 Q.B.Curve // segment 的情况: 为了获得足够快的计算速度,我认为你应该首先考虑使用某种“边界框”算法。 假设 P0 是 Q.B. Curve 的第一个点,P2 是第二个点,P1 是控制点,P3P4 是线段,则:
现在,如果(并且当)您需要精度:
考虑在曲线参数上使用分治算法: P3P4 最近的是哪个? P0P1' 还是 P1'P2?如果是 P0P1',则 t 在 0 和 0.5 之间,因此计算 t=0.25 时的 Pm。 现在 P3P4 最近的是哪个? P0Pm 还是 PmP1'?如果是 PmP1',则计算 t=0.25+0.125=0.375 时的 Pm2,然后最近的是哪个?PmPm2 还是 Pm2P1'?等等。 你将很快得到准确的解决方案,大约需要 6 次迭代,t 的精度为 0.004!当两点之间的距离低于给定值时,可以停止搜索(而不是两个参数之间的差异,因为对于参数的微小变化,点可能相距很远)。 实际上,这种算法的原理是每次更加精确地用线段逼近曲线。对于曲线/曲线,分治法也可以解决,但更难解释,不过你可能会想出来。:=)
希望你能在速度/准确性方面找到良好的平衡。:=)
编辑:我想我找到了一个通用的好方法 :-) 您应该迭代每个B.Q.C.的(内部)边界三角形。 因此,我们有三角形T1,点A、B、C,具有参数tA、tB、tC。 和三角形T2,点D、E、F,具有参数tD、tE、tF。 最初,我们有tA=0 tB=0.5 tC=1.0,T2也是如此,tD=0,tE=0.5,tF=1.0 这个想法是递归调用一个过程,将T1和/或T2分成更小的矩形,直到我们对达到的精度满意为止。 第一步是计算T1到T2的距离,并跟踪哪些线段是每个三角形上最近的。第一个“技巧”:如果在T1上,线段是AC,则停止对T1的递归,曲线1上最近的点是A或C。如果在T2上,最近的线段是DF,则停止对T2的递归,曲线2上最近的点是D或F。如果我们都停止递归->返回距离=min(AD,AF,CD,CF)。然后,如果我们在T1上进行递归,并且线段AB最近,新的T1变为:A'=A B=曲线一上的点,tB=(tA+tC)/2=0.25,C=旧的B。对于T2也是如此:如果需要递归,则应用递归,并在新的T1和新的T2上调用相同的算法。当T1和T2之间找到的距离减去先前T1和T2之间找到的距离低于阈值时停止算法。 该函数可能类似于ComputeDistance(curveParam1, A, C, shouldSplitCurve1, curveParam2, D, F, shouldSplitCurve2, previousDistance),其中点还存储其t参数。
请注意,距离(曲线、线段)只是此算法的一个特例,您应该实现距离(三角形、三角形)和距离(线段、三角形)以使其正常工作。玩得开心。在贝塞尔曲线和直线的情况下
有三个候选点是最接近直线的:
测试所有三个;最短距离获胜。
在两个贝塞尔曲线的情况下
取决于您是否需要精确的分析结果,或者优化的数值结果已经足够好。
分析结果
给定两个贝塞尔曲线A(t)和B(s),您可以推导出它们的本地方向A'(t)和B'(s)的方程。使A'(t) = B'(s)的点对是候选点,即使曲线在本地上平行的(t, s)。我没有检查过,但我认为可以解析地解决A'(t) - B'(s) = 0。如果您的曲线与您在示例中显示的曲线类似,那么该方程应该只有一个解或没有解,但可能会有两个解(或在曲线相同但平移时可能有无限多的解——在这种情况下,您可以忽略这一点,因为获胜者总是其中一个曲线段的端点)。采用与上述曲线线段情况类似的方法,测试这些点对以及曲线段端点。最短距离胜出。
数值结果
假设两个 Bézier 曲线上的点定义为A(t)和B(s)。您想要最小化距离d(t,s)=|A(t)-B(s)|。这是一个简单的二参数优化问题:找到最小化d( t, s)的s和t,并满足约束条件0 ≤ t ≤ 1和0 ≤ s ≤ 1。
由于 d = SQRT( ( xA - xB)² + (yA - yB)²),您还可以通过最小化函数 f( t, s) = [d( t, s)]² 来避免平方根计算。
有许多现成的方法可供选择来解决这类优化问题。
法线相交的点是它们最近的点。我的意思是你画一条垂直于该线的线。如果该线也垂直于曲线,那么交点就是最近的点。