QT实现单个控制点在曲线上的贝塞尔曲线

最终效果:

一共三个文件

main.cpp

cpp 复制代码
#include <QApplication>
#include "SplineBoard.h"
int main(int argc,char** argv) {
    QApplication a(argc, argv);
    SplineBoard b;
    b.setWindowTitle("标准的贝塞尔曲线");
    b.show();

    SplineBoard b2(0.0001);
    b2.show();
    b2.setWindowTitle("控制点在曲线上的贝塞尔曲线");

    b.move(0,0);
    b2.move(800,0);
    return a.exec();
}

SplineBoard.h

cpp 复制代码
#ifndef SPLINEBOARD_H
#define SPLINEBOARD_H
#include <QPainter>
#include <QWidget>
class SplineBoard:public QWidget
{
    Q_OBJECT
public:
    SplineBoard(double terminalRatio = 0.25);

protected:
    void mouseMoveEvent(QMouseEvent* e);
    void mousePressEvent(QMouseEvent* e);
    void mouseReleaseEvent(QMouseEvent* e);
    void paintEvent(QPaintEvent* e);
    int mPressedPos;
    QPointF mStart;
    QPointF mEnd;
    QPointF mCont;
    const double termRatio;
};

#endif // SPLINEBOARD_H

SplineBoard.cpp

cpp 复制代码
#include "SplineBoard.h"
#include <QDebug>
#include <QMouseEvent>
#include <QPainterPath>

static int radius = 8;
static const int PosEmpty = 0;
static const int PosStart = 1;
static const int PosCont = 2;
static const int PosEnd = 4;

static void buildQuadBezier(QPainterPath& pp, const QPointF& p0,const QPointF& p1,
                     const QPointF& p2, qreal term){
    pp.moveTo(p0);
    const qreal a = (term-0.5)*-4;
    const qreal d = (1-2*term)*-4;
    for (qreal t = 0; t < 1.01; t += 0.01) {
        qreal A = a*t*t+(-1-a)*t+1;
        qreal B = d*t*t - d*t;
        qreal C = a*t*t + (1-a)*t;
        qreal x = A * p0.x() + B * p1.x() + C * p2.x();
        qreal y = A * p0.y() + B * p1.y() + C * p2.y();
        pp.lineTo(x, y);
    }
}
SplineBoard::SplineBoard(double terminalRatio):mPressedPos(PosEmpty),termRatio(terminalRatio)
{
    resize(800,600);
    setWindowTitle("spline board");

    mStart = QPointF(50,300);
    mEnd = QPointF(750,300);
    mCont = QPointF(400,300);
}

void SplineBoard::mouseMoveEvent(QMouseEvent* e){
    auto cur = e->pos();
    if(mPressedPos == PosStart){
        mStart = cur;
    }
    else if(mPressedPos == PosCont){
        mCont = cur;
    }
    else if(PosEnd == mPressedPos){
        mEnd = cur;
    }
    else{
        return;
    }
    update();
}
void SplineBoard::mousePressEvent(QMouseEvent* e){
    auto pos = e->pos();
    auto startRect = QRectF(mStart,QSize(radius*2,radius*2));
    startRect.translate(-radius,-radius);
    auto contRect = QRectF(mCont,QSize(radius*2, radius*2));
    contRect.translate(-radius,-radius);
    auto endRect = QRectF(mEnd , QSize(radius*2, radius*2));
    endRect.translate(-radius,-radius);

    if(startRect.contains(pos)){
        mPressedPos = PosStart;
    }
    else if(contRect.contains(pos)) {
        mPressedPos = PosCont;
    }
    else if(endRect.contains(pos)){
        mPressedPos = PosEnd;
    }
    else{
        mPressedPos = PosEmpty;
    }

}
void SplineBoard::mouseReleaseEvent(QMouseEvent* e){
    mPressedPos = PosEmpty;
}

void SplineBoard::paintEvent(QPaintEvent* e){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    QPen pen(Qt::blue);
    pen.setWidth(2);
    painter.setPen(pen);

    QPainterPath path;

    buildQuadBezier(path,mStart,mCont,mEnd,termRatio);
    painter.drawPath(path);

    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::magenta);
    painter.drawEllipse(mStart,radius,radius);  // Draw start point
    painter.drawEllipse(mCont, radius,radius);  // Draw control point
    painter.drawEllipse(mEnd, radius,radius);  // Draw end point

    QWidget::paintEvent(e);

}
相关推荐
天赐学c语言6 分钟前
12.20 - 反转链表II && 传值和传地址的区别
数据结构·c++·算法·链表·leecode
_OP_CHEN7 分钟前
【算法基础篇】(三十六)图论基础之拓扑排序:从原理到实战,搞定 DAG 图的 “先后次序” 难题
c++·算法·蓝桥杯·图论·拓扑排序·算法竞赛·acm/icpc
YouEmbedded16 分钟前
解码 Qt 交互:滑动交互、窗口拖拽
qt·滑动交互·上滑关闭·滑动显示 / 隐藏
郝学胜-神的一滴18 分钟前
使用EBO绘制图形:解锁高效渲染与内存节省之道
c++·qt·游戏·设计模式·系统架构·图形渲染
!停21 分钟前
数据在内存中的存储(2)
开发语言·c++·算法
量子炒饭大师26 分钟前
Cyber骇客的LIFO深渊与FIFO管道 ——【初阶数据结构与算法】栈与队列
c语言·数据结构·c++·链表
Joy-鬼魅1 小时前
vs调试器设置解决创建共享内存返回错误码5的问题
c++·microsoft·createfilemap·vc
Emilia486.1 小时前
C++ 类与对象:解锁面向对象编程的核心密码(中)
开发语言·c++
开压路机1 小时前
模拟实现反向迭代器
前端·c++
枫叶丹41 小时前
【Qt开发】Qt事件(一)
c语言·开发语言·数据库·c++·qt·microsoft