如何找到贝塞尔曲线的控制点?

问题描述

我需要在 C# (Unity) 中以曲线的形式实现连接。我希望得到与 Miro.com 中的实现尽可能相似的结果(见截图)。

附加曲线后,我计算三次贝塞尔曲线的路径。对于第一段,使用锚点和它连接的对象的偏移量。在这个阶段没有问题。

问题:当通过单击并拖动线段的蓝点之一(见屏幕截图)将曲线分成线段时,它在中间被分成两部分。在两条新曲线的交汇处,形成了一个新的交互(可移动)点,其控制点的切线和坐标未知。每次交互点的位置发生变化(下图中的白点)时,我都需要找到这些控制点的位置。此外,曲线在分割时不应大幅改变其位置,不应形成循环,具有不同长度的控制点向量(我在这里不确定)并尽可能表现得足够好(就像在 Miro 的板上一样)。

我所说的控制点是指贝塞尔线段的 2 个不可见引导点。

我用黑色画了已知的控制点,用红色画了我需要找到的那些。 (Pn - 交互点,Cn - 控制点)

Curved connection in Miro.com

我试图找到它们的算法给出了不正确的控制点距离和方向。

测试了以下算法:

  1. 来自Tacent的插值 - 分离时曲线的跳跃,控制点的方向和缩进量不合适;
  2. Chaikin 算法 - 分离过程中曲线跳跃,创建循环;
  3. 基于猜测的“自定义”插值(考虑到线段起点和终点之间到线段中心的距离,以及起点和终点之间的方向)-具有相同的问题,但看起来比上面的略好。

我怀疑解决方案是使用 Catmull-Rom 样条对这些点进行弦插值,并将结果转换为 Bezier 曲线的点。但是,在实施方面仍然存在问题。

3DMax 的曲线看起来也非常相似。在他们的文档中,我发现只提到了参数曲线。

Curve in 3DMax

Same curve in Miro

我没有使用(或不起作用)的方法

  1. Catmull-Rom 插值;
  2. B 样条插值;
  3. 厄米插值;
  4. De Casteljau 的算法(虽然似乎不是为了这个)

如果能得到任何帮助,我将不胜感激,但我要求提供尽可能多的细节。

解决方法

寻找有用的资源来理解贝塞尔曲线 herehere

为了做你想做的事,我会尝试使用 Catmull-Rom 方法,我认为它比 Bezier 方法简单得多,后者是 itween 资产中使用的方法,它是免费的,而且你实现了大量功能。

如果你想坚持使用贝塞尔曲线并找到控制点,我会告诉你我会怎么做才能找到它们。

对于2个控制点贝塞尔曲线的情况:

P = (1-t)P1 + tP2

要了解控制点 P1(x1,y1) 和 P2(x2,y2),您需要在曲线的已知点中应用该方程。考虑到 2D 方程是向量的,所以每个点提供 2 个方程,一个用于 x,一个用于 y,并且每个点有 4 个未知数,x 和 y。

因此对于曲线的第一个节点 (t=0),您将:

Px = (1-0)P1x + 0*P2x

Py = (1-0)P1y + 0*P2y

对于最后一点(t=1)

Px = (1-1)P1x + 1*P2x

Py = (1-1)P1y + 1*P2y

通过这 4 个方程,我将尝试实现控制点 P1 和 P2。您可以使用 t=0 和 t=1 来完成它,它们是您知道曲线的假设点以及由于 t 值而简化数学的那些点,但是只要您知道这些点,您就应该能够使用任何点确定 t 曲线中的坐标。

如果曲线是 3 个控制点的贝塞尔曲线,则需要 6 个方程来对应 3 个控制点,依此类推。

我认为最好的方法是复合三次曲线组合的曲线,并计算每个块的控制点,但我不确定这一点。

一旦理解了数学并实现了控制点,如果成功,我会尝试在代码中实现。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...