Реализация алгоритма Де Бурса для нахождения точек на B-сплайне

Я работал над этим в течение нескольких недель, но не смог заставить мой алгоритм работать должным образом, и я в своем уме. Вот иллюстрация того, чего я достиг:

введите описание изображения здесь

Если бы все работало, я бы ожидал идеального круга / овала в конце.

Мои точки выборки (белого цвета) пересчитываются каждый раз, когда добавляется новая контрольная точка (желтым цветом). В 4-х контрольных точках все выглядит идеально, опять же, когда я добавляю 5-е число поверх 1-го, все выглядит хорошо, но затем, на 6-м месте, оно начинает уходить и сбоку, а 7-го оно подпрыгивает до начала координат!

Ниже я выложу свой код, где calculateWeightForPointI содержит фактический алгоритм. И для справки- вот информация, которой я пытаюсь следовать. Я был бы так рад, если бы кто-нибудь взглянул на меня.

void updateCurve(const std::vector<glm::vec3>& controls, std::vector<glm::vec3>& samples)
{
int subCurveOrder = 4; // = k = I want to break my curve into to cubics

// De boor 1st attempt
if(controls.size() >= subCurveOrder)
{
createKnotVector(subCurveOrder, controls.size());
samples.clear();

for(int steps=0; steps<=20; steps++)
{
// use steps to get a 0-1 range value for progression along the curve
// then get that value into the range [k-1, n+1]
// k-1 = subCurveOrder-1
// n+1 = always the number of total control points

float t = ( steps / 20.0f ) * ( controls.size() - (subCurveOrder-1) ) + subCurveOrder-1;

glm::vec3 newPoint(0,0,0);
for(int i=1; i <= controls.size(); i++)
{
float weightForControl = calculateWeightForPointI(i, subCurveOrder, controls.size(), t);
newPoint += weightForControl * controls.at(i-1);
}
samples.push_back(newPoint);
}
}

}

//i = the weight we're looking for, i should go from 1 to n+1, where n+1 is equal to the total number of control points.
//k = curve order = power/degree +1. eg, to break whole curve into cubics use a curve order of 4
//cps = number of total control points
//t = current step/interp value
float calculateWeightForPointI( int i, int k, int cps, float t )
{
//test if we've reached the bottom of the recursive call
if( k == 1 )
{
if( t >= knot(i) && t < knot(i+1) )
return 1;
else
return 0;
}

float numeratorA = ( t - knot(i) );
float denominatorA = ( knot(i + k-1) - knot(i) );
float numeratorB = ( knot(i + k) - t );
float denominatorB = ( knot(i + k) - knot(i + 1) );

float subweightA = 0;
float subweightB = 0;

if( denominatorA != 0 )
subweightA = numeratorA / denominatorA * calculateWeightForPointI(i, k-1, cps, t);
if( denominatorB != 0 )
subweightB = numeratorB / denominatorB * calculateWeightForPointI(i+1, k-1, cps, t);

return subweightA + subweightB;

}

//returns the knot value at the passed in index
//if i = 1 and we want Xi then we have to remember to index with i-1
float knot(int indexForKnot)
{
// When getting the index for the knot function i remember to subtract 1 from i because of the difference caused by us counting from i=1 to n+1 and indexing a vector from 0
return knotVector.at(indexForKnot-1);
}
//calculate the whole knot vector
void createKnotVector(int curveOrderK, int numControlPoints)
{
int knotSize = curveOrderK + numControlPoints;
for(int count = 0; count < knotSize; count++)
{
knotVector.push_back(count);
}
}

9

Решение

Ваш алгоритм, кажется, работает для любых входов, которые я попробовал. Ваша проблема может заключаться в том, что контрольная точка находится не там, где она должна быть, или что они не были правильно инициализированы. Похоже, есть две контрольные точки, половина высоты ниже нижнего левого угла.

Правильный
Неправильно

2

Другие решения

Других решений пока нет …