基于距另一点的距离在贝塞尔曲线上找到点

时间:2010-09-10 06:44:04

标签: 3d distance bezier spline

所以我有一个3D立方贝塞尔曲线和沿曲线任意位置找到的起点,需要找到曲线下方的第二个点,即距离第一个点的特定世界空间距离(不是弧长距离)。

另一个问题是,如果第二个点到达曲线的末端并且仍然不在所需的世界空间距离,在这种情况下,我希望它沿着切线继续直到达到距离。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

唉,我不知道任何封闭形式的等式给出你想要的点。 也许最接近该点的最简单的技术是将贝塞尔曲线递归地切割成2条较小的贝塞尔曲线 de Casteljau's algorithm。 任何时候递归都会触底 (a)曲线的所有边界点都离给定点太近或太远,或者 (b)曲线的所有边界点都“足够接近”,等于所需距离(可能它们都适合同一像素)。

我很确定给定贝塞尔曲线上距离某个给定点的给定线性距离的最大点数是4个点。 (当给定的贝塞尔曲线具有自相交时,可能会发生这种情况)。

编辑:

也许我应该在回答之前阅读整个问题,是吗? 标准的“四点”贝塞尔曲线段可以看作是一段无限长的立方曲线。在一个位置可能存在弯曲或环或尖点,但距离该尖锐曲线足够远,路径变平以接近2条直线,每条直线指向任意方向。 唉,上述解决方案只能找到短贝塞尔曲线段上的点。 我假设你想要沿着给定点给定距离的无限长三次曲线上的点,即使它们不在短贝塞尔曲线段上。

== de Casteljau in reverse ==

你可以反向运行(递归中点)de Casteljau的算法,在每次迭代时生成一个新的四点贝塞尔曲线“双”大小,直到你得到一个大到足以包含所需的点。 (当所有4个初始点与给定点“太近”时,则保证加倍最终产生一个曲线段,起点“太近”,终点“太远”,然后你可以使用上面的算法收敛于距离给定点所需距离的点上。 这种方法仅依赖加法,减法,乘以2和平均, 所以原则上它应该具有相对数值的稳健性。 (它实际上从未在任何位置t评估立方公式。)

== zero-finding ==

您可以从四点表示转换为三次多项式表示,并使用任何根寻找算法收敛到其中一个所需的点。 牛顿的方法应该工作得很好,因为贝塞尔曲线的短片几乎是直的。 我们能否适应牛顿方法方程式 Finding the Minimum Distance Between a Point and a Cubic Spline 这个问题? 为了简化描述,我将使用二分算法,即使它比牛顿方法运行得慢。

与往常一样,三次贝塞尔曲线段可以描述为

B(t) = (1-t)^3 * P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3.

(不幸的是,这个等式并不总是在数值上很稳健 - 这就是为什么很多人使用de Casteljau的算法来使用递归减半的原因)。

我假设您已经(或可以找到)给定点的t_given值,

x_given = B(t_given).x
y_given = B(t_given).y

毕达哥拉斯定理给出了给定点与曲线上其他点之间的距离,

distance2(t) = ( x_given - B(t).x )^2 + ( y_given - B(t).y )^2.
distance(t) = sqrt(distance2(t)).

您正在寻找的点位于函数的零点

given_distance2 = given_distance^2.
f(t) = distance2(t) - given_distance2.

假设给定距离不为零,并且给定点具有t_given< 1, 二分算法将运行类似

的算法
left = t_given
right = 1 // the endpoint of the given Bezier curve segment
while( distance2(right) < given_distance2 ){
    right = right*2
}

此时,t_left比所需距离更接近给定点,并且t_right远离所需距离(或者可能完全相等)。 由于我们有一个点太接近,另一个点太远,二分算法应该可以工作。

while( (abs(f(right) is too big) AND (abs(left - right) is too big) ){
    // find midpoint
    midpoint = (t_left + t_right)/2

接下来我们检查:第一段是否离开......中点包含零点,或中点...右?

    if( f(left)*f(midpoint) < 0 ) then
        // throw away right half
        right = midpoint
    else
        // throw away left half
        left = midpoint
}

return( right )

此时,“右”值是t的值,B(右)是对应点,使得从该点到原始给定点的距离是(大约)给定距离。

答案 1 :(得分:1)

您的问题陈述需要更精细化。特别是当你要求某个B点距离起点A N个单位时,你的约束不足。可能有多个距离A的N个点。

除此之外,阻止你沿着曲线以设定的间隔对曲线进行采样,然后计算回到A的线性距离。这不是最佳的,但它会起作用。要处理N个距离以外的多个点,您必须提出一个规则。可能就像发现的第一点一样简单。