Reputation: 1
I am generating a B-spline curve of degree 3 with 10 control points. My knot vector has 14 entries ranging from 0 to 1. For some reason my curve always begins and ends at the origin. It also fails to draw a curve if any knot is equal to another knot.
Here is my code for the basis function:
if( p == 0 ) {
if( (KN[i] <= u) && (u < KN[i+1]) ){
return 1;
}
return 0;
}
else{
u1 = (u - KN[i])/(KN[i+p]-KN[i]);
u2 = (KN[i+p+1]-u)/(KN[i+p+1]-KN[i+1]);
return u1*Basis(i,(p-1),u)+u2*Basis(i+1,p-1,u);
}
where i is the current point (0 through 9), p is the degree, 3, and u is where in my domain [0,1] we are. My curve making function calls this basis function and looks like this:
void makeCurve (int n, int p){
G_rgb(0,1,0);
double u, x, y;
int i;
for(u = 0; u <= 1; u += 0.0001){
x = 0;
y = 0;
for(i = 0; i < n; i ++){
x += Basis(i,p,u) * PX[i];
y += Basis(i,p,u) * PY[i];
}
G_point(x,y);
}
}
where n is the number of points, 10, and p is the degree, 3.
For reference here is the program in its entirety:
double PX[20], PY[20], KN[11];
int factorial( int n )
{
int res, i;
if( n <= 0 ){
return 1 ; // safeguard 0 and -ve
}
res = n ;
for(i = n-1; i > 1; i --){
res *= i;
}
return res;
}
double Basis(int i, int p, double u){
double u1, u2;
if( p == 0 ) {
if( (KN[i] <= u) && (u < KN[i+1]) ){
return 1;
}
return 0;
}
else{
u1 = (u - KN[i])/(KN[i+p]-KN[i]);
u2 = (KN[i+p+1]-u)/(KN[i+p+1]-KN[i+1]);
return u1*Basis(i,(p-1),u)+u2*Basis(i+1,p-1,u);
}
}
void makeCurve (int n, int p){
G_rgb(0,1,0);
double u, x, y;
int i;
for(u = 0; u <= 1; u += 0.0001){
x = 0;
y = 0;
for(i = 0; i < n; i ++){
x += Basis(i,p,u) * PX[i];
y += Basis(i,p,u) * PY[i];
}
G_point(x,y);
}
}
void makeLines(int n){
int i;
G_rgb(1,1,1);
for(i = 0; i < n - 1; i ++){
G_line(PX[i],PY[i],PX[i+1],PY[i+1]);
}
}
void makeDots(int n){
int i;
G_rgb(1,0,0);
for(i = 0; i < n; i ++){
G_fill_circle(PX[i],PY[i],5);
}
}
void main(){
G_init_graphics(800,800);
G_rgb(0,0,0);
G_clear();
double p[2], u;
int i, n, m;
n = 0;
for(i = 0; i < 10; i ++){
G_wait_click(p);
PX[i] = p[0];
PY[i] = p[1];
G_rgb(1,0,0);
G_fill_circle(p[0],p[1],5);
if(i != 0){
G_rgb(1,1,1);
G_line(p[0],p[1],PX[i-1],PY[i-1]);
}
}
// so n = 9 and p = 6 so m = 13 and there are 14 knots
KN[0] = 0;
KN[1] = 0.03;
KN[2] = 0.1;
KN[3] = 0.12;
KN[4] = 0.14;
KN[5] = 0.28;
KN[6] = 0.42;
KN[7] = 0.57;
KN[8] = 0.71;
KN[9] = 0.85;
KN[10] = 0.9;
KN[11] = 0.99;
KN[12] = 0.999;
KN[13] = 1;
makeCurve(10, 3);
while(1 == 1){
if(G_wait_key() == 'q') {
break;
}
}
}
Upvotes: 0
Views: 755
Reputation: 1433
You get a divide by zero error in Basis() when p != 0 but KN[i+p] == KN[i], which is why it doesn't work when the knots are equal, and KN should contain 14 items, not 11.
Both gcc and clang automatically warn you that KN is the wrong size, so you should consider updating your compiler.
Upvotes: 1