diff --git a/0snap/smoothcurve.png b/0snap/smoothcurve.png new file mode 100644 index 0000000..c12cb55 Binary files /dev/null and b/0snap/smoothcurve.png differ diff --git a/QWidgetDemo.pro b/QWidgetDemo.pro index 881835d..3e8dc6d 100644 --- a/QWidgetDemo.pro +++ b/QWidgetDemo.pro @@ -35,6 +35,7 @@ SUBDIRS += screenwidget #屏幕截图控件 SUBDIRS += imageswitch #图片开关控件 SUBDIRS += netserver #网络中转服务器 SUBDIRS += base64 #图片文字base64互换 +SUBDIRS += smoothcurve #平滑曲线 win32 { SUBDIRS += ffmpegdemo #视频流播放ffmpeg内核 diff --git a/README.md b/README.md index 3a0e5d8..849837a 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ | 40 | mpvdemo | 视频流播放mpv内核 | | 41 | miniblink | miniblink示例 | | 42 | base64 | 图片文字base64互换 | +| 43 | smoothcurve | 平滑曲线 | ### 二、学习群 1. **Qt交流大会群 853086607(雨田哥)** @@ -96,4 +97,5 @@ ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/netserver.jpg) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/designer.png) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/miniblink.jpg) -![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/base64.png) \ No newline at end of file +![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/base64.png) +![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/smoothcurve.png) \ No newline at end of file diff --git a/smoothcurve/frmsmoothcurve.cpp b/smoothcurve/frmsmoothcurve.cpp new file mode 100644 index 0000000..ffb9599 --- /dev/null +++ b/smoothcurve/frmsmoothcurve.cpp @@ -0,0 +1,68 @@ +#include "frmsmoothcurve.h" +#include "ui_frmsmoothcurve.h" +#include "smoothcurve.h" +#include "qpainter.h" +#include "qdatetime.h" +#include "qdebug.h" + +frmSmoothCurve::frmSmoothCurve(QWidget *parent) : QWidget(parent), ui(new Ui::frmSmoothCurve) +{ + ui->setupUi(this); + + //初始化随机数种子 + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + //随机生成曲线上的点 + int x = -300; + while (x < 300) { + datas << QPointF(x, qrand() % 300 - 100); + x += qMin(qrand() % 30 + 5, 300); + } + + //根据曲线上的点创建平滑曲线 + smoothCurve = SmoothCurve::createSmoothCurve(datas); + + // 直接连接点的创建非平滑曲线曲线 + smoothCurve2.moveTo(datas[0]); + for (int i = 1; i < datas.size(); ++i) { + smoothCurve2.lineTo(datas[i]); + } + + connect(ui->showKnotsCheckBox, SIGNAL(clicked(bool)), this, SLOT(update())); + connect(ui->showSmoothCurveCheckBox, SIGNAL(clicked(bool)), this, SLOT(update())); +} + +frmSmoothCurve::~frmSmoothCurve() +{ + delete ui; +} + +void frmSmoothCurve::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.translate(width() / 2, height() / 2); + painter.scale(1, -1); + + //画坐标轴 + painter.setPen(QColor(180, 180, 180)); + painter.drawLine(-250, 0, 250, 0); + painter.drawLine(0, 150, 0, -150); + + //被选中时显示平滑曲线,否则显示非平滑曲线 + painter.setPen(QPen(QColor(80, 80, 80), 2)); + if (ui->showSmoothCurveCheckBox->isChecked()) { + painter.drawPath(smoothCurve); + } else { + painter.drawPath(smoothCurve2); + } + + //如果曲线上的点可见则显示出来 + if (ui->showKnotsCheckBox->isChecked()) { + painter.setPen(Qt::black); + painter.setBrush(Qt::gray); + foreach (QPointF p, datas) { + painter.drawEllipse(p, 3, 3); + } + } +} diff --git a/smoothcurve/frmsmoothcurve.h b/smoothcurve/frmsmoothcurve.h new file mode 100644 index 0000000..8639013 --- /dev/null +++ b/smoothcurve/frmsmoothcurve.h @@ -0,0 +1,31 @@ +#ifndef FRMSMOOTHCURVE_H +#define FRMSMOOTHCURVE_H + +#include +#include +#include +#include + +namespace Ui { +class frmSmoothCurve; +} + +class frmSmoothCurve : public QWidget +{ + Q_OBJECT + +public: + explicit frmSmoothCurve(QWidget *parent = 0); + ~frmSmoothCurve(); + +protected: + void paintEvent(QPaintEvent *event); + +private: + Ui::frmSmoothCurve *ui; + QVector datas; //曲线上的点 + QPainterPath smoothCurve; //平滑曲线 + QPainterPath smoothCurve2; //直接连接点的非平滑曲线 +}; + +#endif // FRMSMOOTHCURVE_H diff --git a/smoothcurve/frmsmoothcurve.ui b/smoothcurve/frmsmoothcurve.ui new file mode 100644 index 0000000..324b8b1 --- /dev/null +++ b/smoothcurve/frmsmoothcurve.ui @@ -0,0 +1,62 @@ + + + frmSmoothCurve + + + + 0 + 0 + 714 + 523 + + + + Widget + + + + + + Qt::Vertical + + + + 20 + 473 + + + + + + + + 显示坐标点 + + + + + + + Qt::Horizontal + + + + 549 + 20 + + + + + + + + 平滑 + + + + + + + + + diff --git a/smoothcurve/main.cpp b/smoothcurve/main.cpp new file mode 100644 index 0000000..f3c23d9 --- /dev/null +++ b/smoothcurve/main.cpp @@ -0,0 +1,31 @@ +#pragma execution_character_set("utf-8") + +#include "frmsmoothcurve.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setFont(QFont("Microsoft Yahei", 9)); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmSmoothCurve w; + w.setWindowTitle("平滑曲线"); + w.show(); + + return a.exec(); +} diff --git a/smoothcurve/smoothcurve.cpp b/smoothcurve/smoothcurve.cpp new file mode 100644 index 0000000..fe20c5e --- /dev/null +++ b/smoothcurve/smoothcurve.cpp @@ -0,0 +1,96 @@ +#include "smoothcurve.h" + +QPainterPath SmoothCurve::createSmoothCurve(const QVector &points) +{ + QPainterPath path; + int len = points.size(); + if (len < 2) { + return path; + } + + QVector firstControlPoints; + QVector secondControlPoints; + calculateControlPoints(points, &firstControlPoints, &secondControlPoints); + path.moveTo(points[0].x(), points[0].y()); + + for (int i = 0; i < len - 1; ++i) { + path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i + 1]); + } + + return path; +} + +void SmoothCurve::calculateFirstControlPoints(double *&result, const double *rhs, int n) +{ + result = new double[n]; + double *tmp = new double[n]; + double b = 2.0; + result[0] = rhs[0] / b; + + for (int i = 1; i < n; i++) { + tmp[i] = 1 / b; + b = (i < n - 1 ? 4.0 : 3.5) - tmp[i]; + result[i] = (rhs[i] - result[i - 1]) / b; + } + + for (int i = 1; i < n; i++) { + result[n - i - 1] -= tmp[n - i] * result[n - i]; + } + + delete tmp; +} + +void SmoothCurve::calculateControlPoints(const QVector &datas, + QVector *firstControlPoints, + QVector *secondControlPoints) +{ + int n = datas.size() - 1; + for (int i = 0; i < n; ++i) { + firstControlPoints->append(QPointF()); + secondControlPoints->append(QPointF()); + } + + if (n == 1) { + (*firstControlPoints)[0].rx() = (2 * datas[0].x() + datas[1].x()) / 3; + (*firstControlPoints)[0].ry() = (2 * datas[0].y() + datas[1].y()) / 3; + (*secondControlPoints)[0].rx() = 2 * (*firstControlPoints)[0].x() - datas[0].x(); + (*secondControlPoints)[0].ry() = 2 * (*firstControlPoints)[0].y() - datas[0].y(); + return; + } + + double *xs = 0; + double *ys = 0; + double *rhsx = new double[n]; + double *rhsy = new double[n]; + + for (int i = 1; i < n - 1; ++i) { + rhsx[i] = 4 * datas[i].x() + 2 * datas[i + 1].x(); + rhsy[i] = 4 * datas[i].y() + 2 * datas[i + 1].y(); + } + + rhsx[0] = datas[0].x() + 2 * datas[1].x(); + rhsx[n - 1] = (8 * datas[n - 1].x() + datas[n].x()) / 2.0; + rhsy[0] = datas[0].y() + 2 * datas[1].y(); + rhsy[n - 1] = (8 * datas[n - 1].y() + datas[n].y()) / 2.0; + + calculateFirstControlPoints(xs, rhsx, n); + calculateFirstControlPoints(ys, rhsy, n); + + for (int i = 0; i < n; ++i) { + (*firstControlPoints)[i].rx() = xs[i]; + (*firstControlPoints)[i].ry() = ys[i]; + + if (i < n - 1) { + (*secondControlPoints)[i].rx() = 2 * datas[i + 1].x() - xs[i + 1]; + (*secondControlPoints)[i].ry() = 2 * datas[i + 1].y() - ys[i + 1]; + } else { + (*secondControlPoints)[i].rx() = (datas[n].x() + xs[n - 1]) / 2; + (*secondControlPoints)[i].ry() = (datas[n].y() + ys[n - 1]) / 2; + } + } + + delete xs; + delete ys; + delete rhsx; + delete rhsy; +} diff --git a/smoothcurve/smoothcurve.h b/smoothcurve/smoothcurve.h new file mode 100644 index 0000000..6f69071 --- /dev/null +++ b/smoothcurve/smoothcurve.h @@ -0,0 +1,27 @@ +#ifndef SMOOTHCURVE_H +#define SMOOTHCURVE_H + +#include +#include +#include +#include + +#ifdef quc +class Q_DECL_EXPORT SmoothCurve : public QObject +#else +class SmoothCurve : public QObject +#endif + +{ +public: + //创建平滑曲线路径 + static QPainterPath createSmoothCurve(const QVector &points); + +private: + static void calculateFirstControlPoints(double *&result, const double *rhs, int n); + static void calculateControlPoints(const QVector &datas, + QVector *firstControlPoints, + QVector *secondControlPoints); +}; + +#endif // SMOOTHCURVE_H diff --git a/smoothcurve/smoothcurve.pro b/smoothcurve/smoothcurve.pro new file mode 100644 index 0000000..3a70bfe --- /dev/null +++ b/smoothcurve/smoothcurve.pro @@ -0,0 +1,23 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-01-09T09:29:12 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = smoothcurve +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmsmoothcurve.cpp +SOURCES += smoothcurve.cpp + +HEADERS += frmsmoothcurve.h +HEADERS += smoothcurve.h + +FORMS += frmsmoothcurve.ui