Qt实现圆滑曲线

qt实现圆滑曲线,利用的是贝塞尔曲线(cubicTo)。此函数需要两个两个控制点(重点是实现这两个点的算取)。

本次采用的是QtChart里面的代码实现。具体效果如下:
Qt实现圆滑曲线_第1张图片

算法代码

QVector test1::calculateControlPoints(const QVector &points)
{
    QVector controlPoints;
    controlPoints.resize(points.count() * 2 - 2);

    int n = points.count() - 1;

    if (n == 1) {
        //for n==1
        controlPoints[0].setX((2 * points[0].x() + points[1].x()) / 3);
        controlPoints[0].setY((2 * points[0].y() + points[1].y()) / 3);
        controlPoints[1].setX(2 * controlPoints[0].x() - points[0].x());
        controlPoints[1].setY(2 * controlPoints[0].y() - points[0].y());
        return controlPoints;
    }

    // Calculate first Bezier control points
    // Set of equations for P0 to Pn points.
    //
    //  |   2   1   0   0   ... 0   0   0   ... 0   0   0   |   |   P1_1    |   |   P0 + 2 * P1             |
    //  |   1   4   1   0   ... 0   0   0   ... 0   0   0   |   |   P1_2    |   |   4 * P1 + 2 * P2         |
    //  |   0   1   4   1   ... 0   0   0   ... 0   0   0   |   |   P1_3    |   |   4 * P2 + 2 * P3         |
    //  |   .   .   .   .   .   .   .   .   .   .   .   .   |   |   ...     |   |   ...                     |
    //  |   0   0   0   0   ... 1   4   1   ... 0   0   0   | * |   P1_i    | = |   4 * P(i-1) + 2 * Pi     |
    //  |   .   .   .   .   .   .   .   .   .   .   .   .   |   |   ...     |   |   ...                     |
    //  |   0   0   0   0   0   0   0   0   ... 1   4   1   |   |   P1_(n-1)|   |   4 * P(n-2) + 2 * P(n-1) |
    //  |   0   0   0   0   0   0   0   0   ... 0   2   7   |   |   P1_n    |   |   8 * P(n-1) + Pn         |
    //
    QVector vector;
    vector.resize(n);

    vector[0] = points[0].x() + 2 * points[1].x();


    for (int i = 1; i < n - 1; ++i)
        vector[i] = 4 * points[i].x() + 2 * points[i + 1].x();

    vector[n - 1] = (8 * points[n - 1].x() + points[n].x()) / 2.0;

    QVector xControl = firstControlPoints(vector);

    vector[0] = points[0].y() + 2 * points[1].y();

    for (int i = 1; i < n - 1; ++i)
        vector[i] = 4 * points[i].y() + 2 * points[i + 1].y();

    vector[n - 1] = (8 * points[n - 1].y() + points[n].y()) / 2.0;

    QVector yControl = firstControlPoints(vector);

    for (int i = 0, j = 0; i < n; ++i, ++j) {

        controlPoints[j].setX(xControl[i]);
        controlPoints[j].setY(yControl[i]);

        j++;

        if (i < n - 1) {
            controlPoints[j].setX(2 * points[i + 1].x() - xControl[i + 1]);
            controlPoints[j].setY(2 * points[i + 1].y() - yControl[i + 1]);
        } else {
            controlPoints[j].setX((points[n].x() + xControl[n - 1]) / 2);
            controlPoints[j].setY((points[n].y() + yControl[n - 1]) / 2);
        }
    }
    return controlPoints;
}

QVector test1::firstControlPoints(const QVector& vector)
{
    QVector result;

    int count = vector.count();
    result.resize(count);
    result[0] = vector[0] / 2.0;

    QVector temp;
    temp.resize(count);
    temp[0] = 0;

    qreal b = 2.0;

    for (int i = 1; i < count; i++) {
        temp[i] = 1 / b;
        b = (i < count - 1 ? 4.0 : 3.5) - temp[i];
        result[i] = (vector[i] - result[i - 1]) / b;
    }

    for (int i = 1; i < count; i++)
        result[count - i - 1] -= temp[count - i] * result[count - i];

    return result;
}

具体使用如下:

QVector tplist;
    for (int i = 0; i < 100; ++i)
    {
        tplist.append(QPointF(i*20,100+qrand()%500));
    }
    tplist.append(QPointF(100,120));
    tplist.append(QPointF(120,140));
    tplist.append(QPointF(140,10));
    tplist.append(QPointF(160,170));
    tplist.append(QPointF(180,110));
    tplist.append(QPointF(200,119));
    tplist.append(QPointF(220,110));
    tplist.append(QPointF(240,11));
    tplist.append(QPointF(260,120));
    tplist.append(QPointF(280,140));
    tplist.append(QPointF(300,190));
    tplist.append(QPointF(320,109));
    tplist.append(QPointF(340,19));

    QPainterPath path;
    QPainterPath npath;

    //qt chart 算法
    QVector controlPoints = calculateControlPoints(tplist);    
    path.moveTo(tplist.at(0));

    //splinePath.moveTo(points.at(0));
    for (int i = 0; i < tplist.size() - 1; i++) {
        const QPointF &point = tplist.at(i + 1);
        path.cubicTo(controlPoints[2 * i], controlPoints[2 * i + 1], point);
    }

你可能感兴趣的:(Qt)