实现De Boors算法以在B样条上找到点

时间:2013-04-11 08:55:40

标签: c++ algorithm math curve bspline

我已经在这方面工作了几个星期,但一直无法使我的算法正常工作,我的智慧结束了。以下是我所取得的成就:

enter image description here

如果一切正常,我希望最后有一个完美的圆形/椭圆形。

每次添加新控制点(黄色)时,都会重新计算我的采样点(白色)。在4个控制点,一切看起来都很完美,再次在第一个东西上面加上第5个看起来没问题,但是在第6个它开始偏离侧面而在7日它跳到原点!

下面我将发布我的代码,其中calculateWeightForPointI包含实际算法。作为参考 - here is the information i'm trying to follow.如果有人可以看看我,我会非常感激。

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

1 个答案:

答案 0 :(得分:2)

您的算法似乎适用于我尝试过的任何输入。您的问题可能是控制点不在应有的位置,或者它们尚未正确初始化。它看起来有两个控制点,低于左下角的一半高度。

Correct Wrong