欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

绘制贝塞尔曲线

程序员文章站 2023-12-27 09:06:15
...

我们在做项目的时候很多时候会绘制曲线,本篇文章介绍一种Qt绘制简单的贝塞尔曲线的方法。

程序的示例效果如下:
绘制贝塞尔曲线
拖拽鼠标的控制点可以移动点的位置,可以随意拖拽出自己想要的曲线。(红色的点为曲线的起始和终止点,蓝色的点为贝塞尔曲线的控制点)

头文件,BezierCurve.h

class BezierCurveWidget : public QWidget
{
    Q_OBJECT

public:
    BezierCurveWidget(QWidget *parent = nullptr);
    ~BezierCurveWidget();

protected:
    virtual void paintEvent(QPaintEvent *event) override;
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
    virtual void mouseMoveEvent(QMouseEvent *event) override;

private:
    QPoint m_StartPos;
    QPoint m_EndPos;
    QPoint m_CtrolPos1;
    QPoint m_CtrolPos2;

    bool onClickedStartPos = false;
    bool onClickedEndPos = false;
    bool onClickedCtrol1Pos = false;
    bool onClickedCtrol2Pos = false;

    // 圆的半径
    int m_RInterval = 8;

    // 绘制起始点和控制点
    void drawPoints(QPainter* painter);
    // 根据点获取包围矩形
    QRect getOutSizeRect(QPoint);
    // 绘制连线
    void drawLines(QPainter* painter);
};

源文件,BezierCurve.cpp

BezierCurveWidget::BezierCurveWidget(QWidget *parent)
    :QWidget(parent)
{
    m_StartPos = QPoint(100, 100);
    m_EndPos = QPoint(600, 600);
    m_CtrolPos1 = QPoint(100, 600);
    m_CtrolPos2 = QPoint(600, 100);
}

BezierCurveWidget::~BezierCurveWidget()
{

}

void BezierCurveWidget::paintEvent(QPaintEvent *event)
{
    QPainterPath path;
    path.moveTo(m_StartPos);

    // 添加贝塞尔曲线绘制路径
    path.cubicTo(m_CtrolPos1, m_CtrolPos2, m_EndPos);

    // 设置画笔
    QPainter nPainter(this);
    QPen nPen;
    nPen.setColor(QColor(0, 200, 0));
    nPen.setWidth(4);
    nPainter.setPen(nPen);
    // 设置抗锯齿
    nPainter.setRenderHint(QPainter::Antialiasing, true);

    // 绘制路径
    nPainter.drawPath(path);
    // 绘制起始点和控制点
    drawPoints(&nPainter);
    // 绘制连线
    drawLines(&nPainter);

    return QWidget::paintEvent(event);
}

void BezierCurveWidget::mousePressEvent(QMouseEvent *event)
{
    QPoint nMousePos = event->pos();

    if (getOutSizeRect(m_StartPos).contains(nMousePos))
        onClickedStartPos = true;
    else if (getOutSizeRect(m_EndPos).contains(nMousePos))
        onClickedEndPos = true;
    else if (getOutSizeRect(m_CtrolPos1).contains(nMousePos))
        onClickedCtrol1Pos = true;
    else if (getOutSizeRect(m_CtrolPos2).contains(nMousePos))
        onClickedCtrol2Pos = true;

    return QWidget::mousePressEvent(event);
}

void BezierCurveWidget::mouseReleaseEvent(QMouseEvent *event)
{
    onClickedStartPos = false;
    onClickedEndPos = false;
    onClickedCtrol1Pos = false;
    onClickedCtrol2Pos = false;

    return QWidget::mouseReleaseEvent(event);
}

void BezierCurveWidget::mouseMoveEvent(QMouseEvent *event)
{
    QPoint nMousePos = event->pos();

    if (onClickedStartPos)
        m_StartPos = nMousePos;
    else if (onClickedEndPos)
        m_EndPos = nMousePos;
    else if (onClickedCtrol1Pos)
        m_CtrolPos1 = nMousePos;
    else if (onClickedCtrol2Pos)
        m_CtrolPos2 = nMousePos;
    this->repaint();

    return QWidget::mouseMoveEvent(event);
}

void BezierCurveWidget::drawPoints(QPainter* painter)
{
    painter->save();

    // 红色圆圈绘制起始点
    painter->setPen(QPen(QColor(255, 0, 0)));
    painter->drawEllipse(m_StartPos, m_RInterval, m_RInterval);
    painter->drawEllipse(m_EndPos, m_RInterval, m_RInterval);

    // 蓝色圆圈绘制控制点
    painter->setPen(QPen(QColor(0, 255, 255)));
    painter->drawEllipse(m_CtrolPos1, m_RInterval, m_RInterval);
    painter->drawEllipse(m_CtrolPos2, m_RInterval, m_RInterval);

    painter->restore();
}

void BezierCurveWidget::drawLines(QPainter* painter)
{
    painter->save();

    // 绘制控制点与起始点的连线
    QPen nPen;
    nPen.setStyle(Qt::DotLine);
    nPen.setColor(QColor(200, 100, 100));
    nPen.setWidth(1);
    painter->setPen(nPen);

    painter->drawLine(m_StartPos, m_CtrolPos1);
    painter->drawLine(m_EndPos, m_CtrolPos2);
    painter->drawLine(m_CtrolPos1, m_CtrolPos2);

    painter->restore();
}

QRect BezierCurveWidget::getOutSizeRect(QPoint pos)
{
    int interval = m_RInterval;
    return QRect(pos.x() - interval, pos.y() - interval, 2 * interval, 2 * interval);
}

使用函数void QPainterPath::cubicTo(const QPointF & c1, const QPointF & c2, const QPointF & endPoint)就可以绘制出一条贝塞尔曲线了c1和c2为曲线的控制点,endPoint为曲线的终点,而曲线的起点为当前点。

上一篇:

下一篇: