计算给定控制点的贝塞尔曲线的曲率半径

Blu*_*pud 2 bezier

我正在尝试编写一种以曲率作为优化参数之一的遗传算法。我想根据贝塞尔曲线的控制点计算曲率。我有一个想要优化的最小曲率半径。我一直在引用这篇论文:https ://arxiv.org/pdf/1503.01524.pdf

在论文中,有一个函数可以获取三角形的边长来获取隐含的曲率半径,我已经实现了该函数。这是我当前的代码:

// Computes the curvature implied by 3 control points of a bezier curve
float curvature(float4 p0, float4 p1, float4 p2) {

    // Get the triangle side lengths
    float a = distance(p0, p1);
    float b = distance(p1, p2);
    float c = distance(p2, p0);

    // Do the curvature calculation
    float num = a * b * c;
    float denom = (a + b + c) * (b + c - a) * (a - b + c) * (a + b - c);

    return num / sqrt(denom);

}
Run Code Online (Sandbox Code Playgroud)

这个函数的结果似乎不正确。我对路径中的每个点运行此函数,保存最后两个点,然后获取所有点的最小半径。当我绘制路径时,该函数的计算结果与我直观看到的结果之间似乎存在重大差异。执行此操作的正确方法是什么?

编辑:我正在计算三个控制点之间的曲率半径,而不是曲线中给定点的曲率半径,如果不清楚,我很抱歉。

Mik*_*ans 6

曲率半径 R(t) 等于 1/\xce\xba(t),其中 \xce\xba(t) 是曲线在 t 点的曲率,对于参数化平面曲线为:

\n\n
            x\'y" - y\'x"\n\xce\xba(t)  = --------------------\n         (x\'\xc2\xb2 + y\'\xc2\xb2)^(3/2)\n
Run Code Online (Sandbox Code Playgroud)\n\n

(其中^(3/2)确实是3/2,但您不能在代码块中使用 html 进行上标格式设置,并且 (t) 部分已从 x 和 y 的函数中删除,因为这会使内容变得不必要地难以阅读)

\n\n

因此,对于具有控件 P\xe2\x82\x81、P\xe2\x82\x82 和 P\xe2\x82\x83 的二次贝塞尔曲线,一阶和二阶导数使用以下控制点

\n\n
B(t)\': P\xe2\x82\x81\' = 2(P\xe2\x82\x82 - P\xe2\x82\x81), and P\xe2\x82\x82\' = 2(P\xe2\x82\x83 - P\xe2\x82\x82)\nB(t)": P\xe2\x82\x81" = (P\'\xe2\x82\x82 - P\'\xe2\x82\x81)\n
Run Code Online (Sandbox Code Playgroud)\n\n

评估 x 和 y 的值实际上只是“使用 x 或 y 坐标”,因此:

\n\n
x\' = Px\xe2\x82\x81\'(t-1) + Px\xe2\x82\x82\'(t)\ny\' = Py\xe2\x82\x81\'(t-1) + Py\xe2\x82\x82\'(t)\nx" = Px\xe2\x82\x81"\ny" = Py\xe2\x82\x81"\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意 x" 和 y" 只是常数。我们将这些值代入 \xce\xba(t) 的函数中,当然前提是分母不为零(表示一条线段,没有曲率半径),然后我们就知道 R(t ) 是因为这只是倒数。

\n\n

但我们实际上不需要做任何事情,因为我们可以做一个简单的观察:将圆也视为参数曲线,我们可以根据以下事实立即找到它的半径:曲线的导数与圆在同一点的导数相等。此外,我们知道圆上任何位置导数的长度都相同(因为它是一个圆,根据定义,它关于原点径向对称)。因此,我们可以解决以下问题:

\n\n
B(t)  = P1(1-t)^2 + 2*P2(1-t)t + P3t^2\nB(t)\' = 2*(P2-P1)(1-t) + 2*(P3-P2)t\n\nC(s)  = { r*sin(s), r*cos(s) }independent of \'t\')\nC(s)\' = { r*cos(s), -r*sin(s) }\n\nd = |B(t)\'| = |C(s = any value, so let\'s pick 0)\'|\nd = C(0)\' = | (r,0) | = r\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们就完成了。B(t)点的曲率半径等于B(t)'的向量长度,这样实现起来更容易,运行起来也更快。

\n\n

最后,如果您真正想要的只是用圆弧近似曲线部分,那么https://pomax.github.io/bezierinfo/#arcapproximation 应该涵盖该特定用例的“如何做”。

\n