0

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;
    }
}
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Welcome to Stack Overflow. Please read the [About] page soon. For formatting code on SO, please do not use tabs; it leads to eccentric indentation. Use spaces only, and it is recommended that you indent 4 spaces per level (that's roughly what happens with tabs, anyway). I've had a go at improving the code, but it still would bear some more work. – Jonathan Leffler Apr 28 '14 at 01:05

1 Answers1

1

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.

BonzaiThePenguin
  • 1,413
  • 13
  • 19