Я работал над этим в течение нескольких недель, но не смог заставить мой алгоритм работать должным образом, и я в своем уме. Вот иллюстрация того, чего я достиг:
Если бы все работало, я бы ожидал идеального круга / овала в конце.
Мои точки выборки (белого цвета) пересчитываются каждый раз, когда добавляется новая контрольная точка (желтым цветом). В 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);
}
}
Ваш алгоритм, кажется, работает для любых входов, которые я попробовал. Ваша проблема может заключаться в том, что контрольная точка находится не там, где она должна быть, или что они не были правильно инициализированы. Похоже, есть две контрольные точки, половина высоты ниже нижнего левого угла.
Других решений пока нет …