Bspline 实现未按预期工作
Bspline implementation not working as expected
我实现了 BSPLINE 曲线。我遵循 http://en.wikipedia.org/wiki/B-spline
中给出的通常定义
t 是节点向量。
#include <stdio.h>
double N(int i, int k, double u, double t[])
{
if(k == 1)
{
if(u >= t[i] && u < t[i+1])
return 1.0e0;
else {
return 0.0e0;
}
}
return ((u - t[i])*N(i, k -1, u, t))/(t[i+k-1] - t[i]) + ((t[i+k] - u)*N(i+1, k-1, u, t))/(t[i+k] - t[i+1]);
}
double pu(double u, double x[], int n, int k, double t[])
{
int i;
double r = 0.0e0;
for(i = 0; i < n; i++)
{
r += x[i]*N(i, k, u, t);
}
return r;
}
int main()
{
double t[] = {0.0, 0.5, 1, 2, 3, 4, 4.5, 5}; //knot vector
double x[] = {-30.0, 25.0, 9.0, 20.0, 25.0, 31.0}, y[] = {-5.0, -10.0, 3.0, -10.0, -5.0, 25.0}; //the points
double u;
for(u = 0.0e0; u < 5.0; u+=0.01e0)
{
printf("%lf %lf\n", pu(u, x, 6, 2, t), pu(u, y, 6, 2, t));
}
return 0;
}
问题是,当我绘制计算点时,我发现曲线的起点和终点有意外行为。
例如:
我不明白为什么会这样,尝试更改 t 的值,但似乎不是这样。
一般来说:如果你有 n 个控制点并且你构建了一个 k 阶的 bspline 曲线,你的结向量有 n+k+1 个结。曲线的域(即基函数的总和 =1)在区间 [t_k, ... t_n] 中给出(据我的详细信息是正确的)。
在循环中,您的参数值范围为 0.0 到 5.0。这应该是 t[k] = t[2] = 1.0 到 t[n] = t[6] = 4.0。
Wiki 示例以另一种方式进行,因为那里给出的结向量在开始和结束时有多个值(即 k 次)。因此显示的样条曲线 starts/ends 在 first/last 控制点。你的构造没有给这个 属性.
bspline 有两种实现:统一的和标准的。在 uniform 中,第一个和最后一个控制点不被插值,而在标准结序列中,两个控制点都被插值。在制服中,你可以有统一的结,通常是 1,2,3,... 对于标准结序列,如果你有阶数 k(度数 k-1),你应该有 k 个零,k 个,并在中间填充 1/( m-k+2) 其中 m 是控制点的数量。例如,有 5 个控制点和 3 阶,节点序列为 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1.
此外,使用 delta 函数可以实现比计算 N 函数更好的实现。 Delta 函数受益于 bspline 的本地支持。我建议你看看我在卡尔加里大学教的课程笔记:
http://pages.cpsc.ucalgary.ca/~amahdavi/pmwiki-2.2.8/uploads/Site/notes1.pdf
查看第40页算法3.3。
希望对您有所帮助。
我实现了 BSPLINE 曲线。我遵循 http://en.wikipedia.org/wiki/B-spline
中给出的通常定义t 是节点向量。
#include <stdio.h>
double N(int i, int k, double u, double t[])
{
if(k == 1)
{
if(u >= t[i] && u < t[i+1])
return 1.0e0;
else {
return 0.0e0;
}
}
return ((u - t[i])*N(i, k -1, u, t))/(t[i+k-1] - t[i]) + ((t[i+k] - u)*N(i+1, k-1, u, t))/(t[i+k] - t[i+1]);
}
double pu(double u, double x[], int n, int k, double t[])
{
int i;
double r = 0.0e0;
for(i = 0; i < n; i++)
{
r += x[i]*N(i, k, u, t);
}
return r;
}
int main()
{
double t[] = {0.0, 0.5, 1, 2, 3, 4, 4.5, 5}; //knot vector
double x[] = {-30.0, 25.0, 9.0, 20.0, 25.0, 31.0}, y[] = {-5.0, -10.0, 3.0, -10.0, -5.0, 25.0}; //the points
double u;
for(u = 0.0e0; u < 5.0; u+=0.01e0)
{
printf("%lf %lf\n", pu(u, x, 6, 2, t), pu(u, y, 6, 2, t));
}
return 0;
}
问题是,当我绘制计算点时,我发现曲线的起点和终点有意外行为。
例如:
我不明白为什么会这样,尝试更改 t 的值,但似乎不是这样。
一般来说:如果你有 n 个控制点并且你构建了一个 k 阶的 bspline 曲线,你的结向量有 n+k+1 个结。曲线的域(即基函数的总和 =1)在区间 [t_k, ... t_n] 中给出(据我的详细信息是正确的)。
在循环中,您的参数值范围为 0.0 到 5.0。这应该是 t[k] = t[2] = 1.0 到 t[n] = t[6] = 4.0。
Wiki 示例以另一种方式进行,因为那里给出的结向量在开始和结束时有多个值(即 k 次)。因此显示的样条曲线 starts/ends 在 first/last 控制点。你的构造没有给这个 属性.
bspline 有两种实现:统一的和标准的。在 uniform 中,第一个和最后一个控制点不被插值,而在标准结序列中,两个控制点都被插值。在制服中,你可以有统一的结,通常是 1,2,3,... 对于标准结序列,如果你有阶数 k(度数 k-1),你应该有 k 个零,k 个,并在中间填充 1/( m-k+2) 其中 m 是控制点的数量。例如,有 5 个控制点和 3 阶,节点序列为 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1.
此外,使用 delta 函数可以实现比计算 N 函数更好的实现。 Delta 函数受益于 bspline 的本地支持。我建议你看看我在卡尔加里大学教的课程笔记: http://pages.cpsc.ucalgary.ca/~amahdavi/pmwiki-2.2.8/uploads/Site/notes1.pdf
查看第40页算法3.3。
希望对您有所帮助。