Кривая B-сплайна заканчивается и начинается в начале координат?

Я создаю кривую B-сплайна степени 3 с 10 контрольными точками. Мой вектор узлов содержит 14 записей в диапазоне от 0 до 1. По какой-то причине моя кривая всегда начинается и заканчивается в начале координат. Также не удается нарисовать кривую, если какой-либо узел равен другому узлу.

Вот мой код для базовой функции:

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);
}

где i - текущая точка (от 0 до 9), p - степень, 3, и u - где в моей области [0,1] мы находимся. Моя функция создания кривой вызывает эту базовую функцию и выглядит так:

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);
    }
}

где n - количество точек, 10, а p - степень, 3.

Для справки вот программа в полном объеме:

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;
    }
}
}

1 ответ

Вы получаете ошибку деления на ноль в Basis(), когда p!= 0, но KN[i+p] == KN[i], поэтому она не работает, когда узлы равны, а KN должен содержать 14 элементов не 11

И gcc, и clang автоматически предупреждают вас, что KN имеет неправильный размер, поэтому вам следует подумать об обновлении вашего компилятора.

Другие вопросы по тегам