圆弧的 NURBS 曲线

问题描述 投票:0回答:1

我尝试实现 NURBS 来描述圆弧(此处为圆弧的 1/4)。不幸的是,NURBS 曲线与真实弧线有点远。我期望它会像这里一样更加封闭,例如,https://nurbscalculator.in/或在科学论文中。 我的实现如下图 绿色是NURBS曲线,红色是精确的圆弧。代码如下。也许你会有些想法我错了。我玩了knotVector,但没有成功。

void GLWidget::NURBS()
{
// NURBS test
        glPushMatrix();
        glLineWidth(5.0);

        glColor3f (0.0, 1.0, 0.0);

        std::vector<float> knotVector = {0.0f, 0.125f, 0.125f, 0.5f, 0.5f, 1.0f};
//        std::vector<float> knotVector = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};

        int nknots = knotVector.size();

        std::vector<float> controlPoints = {30.0f,  20.0f, 0.0f, 1.0f,
                                            50.0f,  20.0f, 0.0f, 0.707f,
                                            50.0f,   0.0f, 0.0f, 1.0f};

// NURBS degree
        int degree = 2;
// define the parameter values along the curve
        float tMin = knotVector[degree];
        float tMax = knotVector[nknots - degree - 1];
//        float tMax = knotVector[nknots - 1];
// number of points
        int numPoints = 100;
// step
        float dt = (tMax - tMin) / numPoints;
// curve points
        QVector<float> curvePoints;

        for (float t = tMin; t <= tMax; t += dt)
        {
// span calculation
            int span = findSpan(knotVector, nknots, degree, t);
//basis calculation
            QVector<float> basisFunctions = calculateBasisFunctions(knotVector, span, t, degree);

            qDebug() << "basisFunctions"<< basisFunctions;
            qDebug() << "span" << span;

// accumulate the control points multiplied by the basis function values
            QVector<float> curvePoint(4, 0.0f);
            for (int i = 0; i <= degree; ++i)
            {
                float basis = basisFunctions[i];
                for (int j = 0; j < 4; ++j)
                {
                    curvePoint[j] += controlPoints[(span - degree + i) * 4 + j] * basis;
                }
            }

// add the curve point to the vector
            curvePoints += curvePoint;
        }

// paint the NURBS curve
        glBegin(GL_LINE_STRIP);
        for (int i = 0; i < curvePoints.size(); i += 4)
        {
            glVertex3f(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
        }
        glEnd();

        update();
}

int GLWidget::findSpan(const std::vector<float>& knots, int n, int degree, float t)
{
    if (t >= knots[n-1])
            return n - degree - 2;
        else if (t <= knots[degree])
            return degree;

        int low = degree;
        int high = n;
        int mid = (low + high) / 2;

        while (t < knots[mid] || t >= knots[mid+1])
        {
            if (t < knots[mid])
                high = mid;
            else
                low = mid;
            mid = (low + high) / 2;
        }
        return mid;
}

QVector<float> GLWidget::calculateBasisFunctions(const std::vector<float>& knots, int span, float t, int degree)
    {
        QVector<float> basisFunctions(degree + 1, 0.0f);
        QVector<float> left(degree + 1, 0.0f);
        QVector<float> right(degree + 1, 0.0f);

        basisFunctions[0] = 1.00f;

            for (int j = 1; j <= degree; ++j)
            {
            left[j] = t - knots[span + 1 - j];
            right[j] = knots[span + j] - t;

            float saved = 0.0f;

                for (int r = 0; r < j; ++r)
                {
                float temp = basisFunctions[r] / (right[r + 1] + left[j - r]);
                basisFunctions[r] = saved + right[r + 1] * temp;
                saved = left[j - r] * temp;
                }

            basisFunctions[j] = saved;
            }

       return basisFunctions;
    }
geometry nurbs
1个回答
0
投票

好的,我找到了解决方案。它的工作半径 = 1 单位。之后,插值圆弧可以缩放和移动。

© www.soinside.com 2019 - 2024. All rights reserved.