我有一个非常简单的案例,其中我需要绘制一个单一的2度的均匀B样条曲线段(4个控制点),并且我尝试在C#(https://en.wikipedia.org/wiki/De_Boor%27s_algorithm)中实现deBoor算法。遇到了一个问题,没有大量的阅读和研究帮助我了解正在发生的事情。
在我的情况下,我在Point []数组中仅定义了4个控制点(p1,p2,p3和p4)。所以我只需要点p2和p3之间的曲线段。因此,我构建了一个统一的结点数组,而没有前结和尾结[0,1,2,3]-在这种情况下,我基本上可以只使用i,但是为了坚持公式,我这样做了。 我从Wikipedia构建了递归公式的实现:
看起来像这样:
Point deBoor(int i, int k, float t, int[] knots)
{
//i - knot span index
//k - degree
// t - time [0-knots.Length-1]
//knots - the knots array
if (k == 0) return points[knots[i]]/3f;
return ((t - knots[i]) / (knots[i + k] - knots[i])) * deBoor(i, k - 1, t, knots) + ((knots[i + k + 1] - t) / (knots[i + k + 1] - knots[i + 1])) * deBoor(i + 1, k - 1, t, knots);
}
我试图从deBoor方法中得到这样的点:
float t = time * (points.Length - 1); //time ranges from 0 to 1
int[] knots = new int[] { 0, 1, 2, 3 };
point = deBoor(0, 2, t, knots);
不幸的是,我得到的结果不正确。此图显示了我的控制点的外观,期望得到的以及实际得到的:
我查看了其他实现,例如:https://gist.github.com/soraphis/61ee9185416ee23d0d40,它们似乎都执行相同的工作,只是编码方式不同。我试图复制他们的解决方案,但结果却更糟。所有这些使我觉得我缺少明显痛苦的东西。
答案 0 :(得分:1)
您似乎在混淆节点和控制点。有几件事情,我们需要在你的解决方案来完善,以使其正常工作。
如已经由@fang注意到,您的溶液k==0
是奇怪。我建议更换
if (k == 0) return points[knots[i]]/3f;
接近原始公式,例如
if (k==0)
{
if (t <= knots[i] && t < knots[i+1])
return 1;
else
return 0;
}
正如@fang所指出的,对于具有四个控制点的二次样条,您需要七个结。您提到您想要统一的结,根据您的期望图片,我建议
int[] knots = new float[] {0, 1/6, 2/6, 3/6, 4/6, 5/6, 1};
请注意,结现在在0和1之间;这意味着t
和time
将是相同的,即
float t = time; //time ranges from 0 to 1 and so does t
如果您坚持使用int
(IMHO,这是造成您混乱的原因)
int[] knots = new int[] { 0, 1, 2, 3, 4, 5, 6 };
float t = time * 6; //time ranges from 0 to 1 and t from 0 to 6
请注意互换的顺序:t
必须按time
缩放以覆盖整个结节。
De Boor算法评估一个 B样条,即基函数之一(某些人使用了一个有冲突的命名法,并且对整个样条函数使用单词B样条,而不仅仅是一个基本功能;这有时会导致混淆。
非正式地说,对于给定的t
,您的deBoor
函数为您提供第i
个控制点的系数,它是一个标量。因此,deBoor
的返回值必须是float
或double
或类似的东西,当然也不能是point
。
对于每个t
,您需要对按这些系数缩放的控制点求和。所以您的最终结果将是类似
point value = deBoor(0, 2, t, knots) * points[0]
+ deBoor(1, 2, t, knots) * points[1]
+ deBoor(2, 2, t, knots) * points[2]
+ deBoor(3, 2, t, knots) * points[3];
请注意,*
表示float
和point
的乘法(您可能需要重载这样的运算符),而+
表示两个{{ 1}} s(同样,可能需要运算符重载)。我不是很用C#精通,所以有可能把它写下来的更优雅的方式;例如,我邀请您使用point
循环。
如果仍然感到困惑,我建议您先熟悉贝塞尔曲线,然后再进行B样条曲线。例如,here可以找到相对简洁的介绍。这些照片是有点90年代的风格,但思想仍然有效和易于理解和简洁的方式呈现。