如何选择控制点距离以优化3D立方Bézier曲线的“圆润度”?

4
假设我想构建一个三维立方体贝塞尔曲线,已知两个端点和两个控制点的方向(法向量)。如何选择两个控制点到各自端点的距离,使曲线尽可能“圆滑”?
“圆滑”的形式化定义是:最大化曲线中任意两条线段之间的最小角度。例如,具有端点(10,0,0)(0,10,0)以及相应的法向量(0,1,0)(1,0,0)应产生一个90°的圆弧。对于二维圆弧的特定情况,我找到了像这样的文章。但我没有找到更一般情况下的解决方案。

too big     too small     just right

请注意,这些图片仅用于说明“圆滑度”概念。我的曲线不能保证平面对齐。我可能会稍后更换图片以更好地说明这一点。
这是一个美学问题,如果真正的解决方案未知或过于复杂,我将接受合理的近似值。我的当前近似值过于简单:为两个端点之间距离的一半选择相同的控制点距离。数学更熟悉的人可能能够想出更好的方法。
(附注:这是为开源软件而做的,我很乐意在GitHub上给予荣誉。)
编辑:这里有一些其他图像来说明3D情况(jsfiddle):

bad     good

编辑2:这是一个不稳定版本的ApiNATOMY的截图,让您了解我正在尝试做什么。我正在创建3D管道来代表血管,连接解剖图的不同部分:

ApiNATOMY with 3D blood-vessels

(They won't let me put in a jsfiddle link if I don't include code...)

我投票关闭此问题,因为这是一个数学问题,应该在math.stackexchange上发布。 - Rob
@Rob:数学和计算机科学之间有一条微妙的界线。我在Stack Overflow上看到了很多类似这样的问题,例如如何在两个三次贝塞尔曲线之间找到交点、如何在三次贝塞尔曲线上找到最近的点以及如何偏移三次贝塞尔曲线等等。当我在寻找自己问题的答案时,我发现了这些问题。 - mhelvens
此外,我认为我会更容易理解来自程序员的答案,而不是来自数学家的答案。(话虽如此,如果必须移动,能否将其移至math.stackexchange?) - mhelvens
我觉得SO可以向你展示如何编写代码来解决你的问题,但是它背后的数学知识应该在其他交流平台上讨论。我同意它应该被移动而不是关闭,但是我没有选项可以将其发布为那样的帖子。 - Rob
这个问题的数学答案对程序员来说几乎完全没有用处。这个问题应该保持原样,使用程序员的答案,而不是数学家的答案。数学家会给出公式,程序员仍然需要将其简化为对计算机有意义的步骤。 - Mike 'Pomax' Kamermans
显示剩余4条评论
3个回答

1
你基本上要求的是在样条线上曲率尽可能恒定。
具有恒定曲率的曲线只是一个圆弧,因此尝试将这样的圆弧适配到您的输入参数是有意义的。在2D中,这很容易:构造通过起始点并垂直于所需方向向量的线。对于结束点也做同样的操作。现在相交这两条线:结果是通过两个具有所需方向向量的点的圆的中心。
在你的例子中,这个交点就是(0,0),所需的圆弧位于单位圆上。
因此,这给出了一个圆弧,您可以直接使用或使用您已经引用的近似算法。
当两个方向向量共线时,这将会失效,因此如果这种情况发生,您需要稍微修改一下。如果它们互相指向,则可以简单地使用一条直线。
在三维空间中,同样的建构方法会得到通过端点的两个平面。将它们相交,就能得到一条直线;在这条直线上,选择距离两个点的平方和最小的点。这样就能得到一个与两个端点都相切的球的圆心,然后就可以在由这三个点构成的平面上操作,按照二维空间的方法进行处理。

很抱歉,您过于简化了问题。"结果是通过两点的圆心" - 只有当方向向量"相互镜像"时才成立,而这种情况并不总是发生(http://www.webreference.com/dlab/9902/f1.gif)。在三维空间中,情况变得更加复杂。你可能最终会得到一条无法放在一个平面上的三维曲线。 - mhelvens
@mhelvens:这是真的,我忽略了这一点。在你提到的二维情况中,人们必须在各自的法线上拟合两个圆,但距离各自的端点相同,并且它们只是轻触。这将给您所需的曲率。 - cfh

0

对于特殊情况,即两个端点和控制点的两个已知法向量恰好使贝塞尔曲线成为平面曲线的情况,您基本上正在寻找一个可以很好地近似圆弧的三次贝塞尔曲线。 对于这种特殊情况,您可以将控制点与它们各自的端点之间的距离(表示为L)设置为L =(4/3)* tan(A / 4),其中A是圆弧的角度。

对于一般的3D情况,也许您可以应用相同的公式:

  • 计算两个法向量之间的角度。
  • 使用L =(4/3)* tan(A / 4)来确定您的控制点的位置。

这并不完全正确。那个 L 只适用于第一个控制点,而第二个控制点有一个更为复杂的函数 - Mike 'Pomax' Kamermans
如果第二个控制点和终点之间的距离具有“更复杂”的函数,则近似的贝塞尔曲线不再对被近似的圆弧的平分线对称。不确定这是否是一个好的近似。 - fang
抱歉,我看错了;但仅知道端点为4/3*tan(phi/4)并不能真正帮助原始发布者弄清控制点的函数是什么,这似乎是实际问题,因此这个答案缺少信息(作为一个编程问题,这是必要的信息。作为数学问题的答案,这个答案可以工作,但这不是数学交换。从这个提示中无法期望Stackoverflow的受众弄清楚数学)。 - Mike 'Pomax' Kamermans
曲线是平面的情况很少见。但即使我们坚持这种情况,我不明白为什么你和cfh都在谈论近似一个“圆弧”,当有明显的情况看起来...值得怀疑? - mhelvens
我同意贝塞尔曲线明显不接近圆弧的情况确实存在。但是,无论您用什么公式来确定控制点与它们各自的端点之间的距离,当贝塞尔曲线变成圆弧近似(例如您图片所示的示例)时,这个公式需要很好地工作。这就是我建议首先使用(4/3)*tan(A/4)公式的原因。如果它也适用于一般的3D情况,那么你就得到了答案。如果不行,也许可以从该公式进行一些修改。 - fang
这肯定是最终答案的线索。 :-) - mhelvens

0

如果你的法线在一个平面上对齐

你所做的基本上是在三维空间中创建一个椭圆弧,其中“它在三维空间中”的部分完全无关紧要,因为它只是一个二维曲线,旋转/平移以适应你的三维空间。因此,让我们先解决2D情况,然后RT完全由你决定。

在一条弧上创建“完美”的三次贝塞尔曲线有限制。你基本上不能创建跨越四分之一圆的好看的弧线。因此,有了这个说法:你的起点和终点法线给出了你的法向量之间的2D角度,这与你的起点和终点切线之间的角度相同(因为法线垂直于切线)。所以,让我们:

  1. 将我们的曲线对齐,使起点处的切线为0
  2. 将切线之间的角度插入到Bezier曲线入门中给出的圆近似公式中。这基本上只是愚蠢的实现公式c1x/c1y/c2x/c2y作为一个以角度为参数并输出四个值作为c1(x,y)和c2(x,y)坐标的函数。
  3. 没有第三步,我们完成了。

在第二步之后,您可以在2D中获得控制点,以创建起点和终点之间最圆形的弧。现在,您只需要在3D中进行缩放/旋转/平移,使其与您需要的起点和终点对齐即可。

如果您的法线不在同一平面上

现在我们有一个问题,虽然我们可以通过将维度视为完全独立的事物来处理它。我们不再创建单个2D曲线,而是创建三个:一个是X/Y投影,一个是X/Z投影,另一个是Y/Z投影。对于这三个,我们将以完全相同的方式抽象控制点,然后我们只需取投影控制点(每个控制点三个),然后说“好的,我们现在有X、Y和Z投影坐标。这意味着我们有了(X,Y,Z)坐标”,然后再次完成。

有趣。第一次阅读后我不确定是否理解,但我很快会仔细看看! - mhelvens
请注意,此方法适用于起始和结束切线允许圆弧的情况。正如Fang所指出的那样,还有一些“S”形曲线不包含在此方法中。 - Mike 'Pomax' Kamermans
啊,所以这就是为什么我第一次阅读后没有理解的原因。 :-) 另外两个答案也假设了一个圆弧。但那只是在两个方向向量“镜像彼此”以允许圆形的非常特定情况下的答案。我想我只能责怪我过于简单化的例子。我很快就会修复它。 - mhelvens
请注意,在许多情况下,只要投影允许圆弧,这将很好地运行,只有在法线不像您添加到原始问题的图像时,事情才会出错。例如,像https://dev59.com/v4Lba4cB1Zd3GeqPirwB#25458216中的形状,在XY平面上近似为弧形投影,但在XZ和YZ上投影为“S”。 - Mike 'Pomax' Kamermans
“S”形状是由特定的起点和终点(切线/位置)对以及控制点的放置引起的,因此,可以导致“S”曲线的起始/结束对不一定会这样做,这取决于您将控制点放置多远,这是一种审美考虑。您想用这些类型的点做什么?(也许值得在原始问题中描述,以便每个人都可以在他们的答案中涵盖该情况?) - Mike 'Pomax' Kamermans
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接