最终效果:
一共三个文件
main.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
#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
#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);
}