文章目录

  • 一、生成平滑曲线
  • 二、drawLinePlot函数的修改
  • 三、setSmooth函数

在QCustomPlot中,并没有为我们提供平滑曲线,所以需要我们改造它

注意:改造需要修改源码
注意:改造需要修改源码
注意:改造需要修改源码

一、生成平滑曲线

2020-6-6日更新修复当数据中有NaN的数据时平滑曲线的显示问题
来源:公孙二狗 ,在这里感谢狗哥
生成平滑曲线的方法我也不知道,反正拿来用就是了

class SmoothCurveGenerator
{
protected:static QPainterPath generateSmoothCurveImp(const QVector<QPointF> &points) {QPainterPath path;int len = points.size();if (len < 2) {return path;}QVector<QPointF> firstControlPoints;QVector<QPointF> secondControlPoints;calculateControlPoints(points, &firstControlPoints, &secondControlPoints);path.moveTo(points[0].x(), points[0].y());// Using bezier curve to generate a smooth curve.for (int i = 0; i < len - 1; ++i) {path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i+1]);}return path;}
public:static QPainterPath generateSmoothCurve(const QVector<QPointF> &points) {QPainterPath result;int segmentStart = 0;int i = 0;int pointSize = points.size();while (i < pointSize) {if (qIsNaN(points.at(i).y()) || qIsNaN(points.at(i).x()) || qIsInf(points.at(i).y())) {QVector<QPointF> lineData(QVector<QPointF>(points.constBegin() + segmentStart, points.constBegin() + i - segmentStart));result.addPath(generateSmoothCurveImp(lineData));segmentStart = i + 1;}++i;}QVector<QPointF> lineData(QVector<QPointF>(points.constBegin() + segmentStart, points.constEnd()));result.addPath(generateSmoothCurveImp(lineData));return result;}static QPainterPath generateSmoothCurve(const QPainterPath &basePath, const QVector<QPointF> &points) {if (points.isEmpty()) return basePath;QPainterPath path = basePath;int len = points.size();if (len == 1) {path.lineTo(points.at(0));return path;}QVector<QPointF> firstControlPoints;QVector<QPointF> secondControlPoints;calculateControlPoints(points, &firstControlPoints, &secondControlPoints);path.lineTo(points.at(0));for (int i = 0; i < len - 1; ++i)path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i+1]);return path;}static void 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;// Decomposition and forward substitution.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]; // Backsubstitution.}delete[] tmp;}static void calculateControlPoints(const QVector<QPointF> &knots,QVector<QPointF> *firstControlPoints,QVector<QPointF> *secondControlPoints) {int n = knots.size() - 1;firstControlPoints->reserve(n);secondControlPoints->reserve(n);for (int i = 0; i < n; ++i) {firstControlPoints->append(QPointF());secondControlPoints->append(QPointF());}if (n == 1) {// Special case: Bezier curve should be a straight line.// P1 = (2P0 + P3) / 3(*firstControlPoints)[0].rx() = (2 * knots[0].x() + knots[1].x()) / 3;(*firstControlPoints)[0].ry() = (2 * knots[0].y() + knots[1].y()) / 3;// P2 = 2P1 – P0(*secondControlPoints)[0].rx() = 2 * (*firstControlPoints)[0].x() - knots[0].x();(*secondControlPoints)[0].ry() = 2 * (*firstControlPoints)[0].y() - knots[0].y();return;}// Calculate first Bezier control pointsdouble *xs = nullptr;double *ys = nullptr;double *rhsx = new double[n]; // Right hand side vectordouble *rhsy = new double[n]; // Right hand side vector// Set right hand side valuesfor (int i = 1; i < n - 1; ++i) {rhsx[i] = 4 * knots[i].x() + 2 * knots[i + 1].x();rhsy[i] = 4 * knots[i].y() + 2 * knots[i + 1].y();}rhsx[0] = knots[0].x() + 2 * knots[1].x();rhsx[n - 1] = (8 * knots[n - 1].x() + knots[n].x()) / 2.0;rhsy[0] = knots[0].y() + 2 * knots[1].y();rhsy[n - 1] = (8 * knots[n - 1].y() + knots[n].y()) / 2.0;// Calculate first control points coordinatescalculateFirstControlPoints(xs, rhsx, n);calculateFirstControlPoints(ys, rhsy, n);// Fill output control points.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 * knots[i + 1].x() - xs[i + 1];(*secondControlPoints)[i].ry() = 2 * knots[i + 1].y() - ys[i + 1];} else {(*secondControlPoints)[i].rx() = (knots[n].x() + xs[n - 1]) / 2;(*secondControlPoints)[i].ry() = (knots[n].y() + ys[n - 1]) / 2;}}delete xs;delete ys;delete[] rhsx;delete[] rhsy;}
};

二、drawLinePlot函数的修改

mSmooth为我们添加的一个bool型的类成员变量,并且我们限制了QCPGraph的线风格mLineStylelsLine的时候才会真正的绘制平滑曲线

void QCPGraph::drawLinePlot(QCPPainter *painter, const QVector<QPointF> &lines) const
{if (painter->pen().style() != Qt::NoPen && painter->pen().color().alpha() != 0) {applyDefaultAntialiasingHint(painter);if (mSmooth && mLineStyle == lsLine) painter->drawPath(SmoothCurveGenerator::generateSmoothCurve(lines));else drawPolyline(painter, lines);}
}

这时候已经可以实现平滑曲线了,来个简单的例子看下

void MainWindow::setupSmoothCurveDemo(QCustomPlot *customPlot)
{QVector<double> xdata = { 1, 2, 3, 4, 5, 6, 7 };QVector<double> ydata = { 820, 932, 901, 934, 1290, 1330, 1320 };QCPGraph *graph = customPlot->addGraph();graph->setPen(QPen(Qt::red, 2));graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QColor(Qt::red), QColor(Qt::white), 6));graph->setData(xdata, ydata);graph->setSmooth(true);   // 开启平滑曲线customPlot->xAxis->setRange(0, 8);customPlot->yAxis->setRange(0, 1500);
}

三、setSmooth函数

鉴于很多人说不知道setSmooth函数是什么,特地放上来的!!!
mSmooth是我们自己新增的QCPGraph的一个bool型成员变量
mSmooth是我们自己新增的QCPGraph的一个bool型成员变量
mSmooth是我们自己新增的QCPGraph的一个bool型成员变量

// QCPGraph.h头文件
class QCP_LIB_DECL QCPGraph : public QCPAbstractPlottable1D<QCPGraphData>
{
public: void setSmooth(bool smooth);             // 新增内容
protected:bool mSmooth;                            // 新增内容
}
// QCPGraph.cpp源文件
void QCPGraph::setSmooth(bool smooth)
{mSmooth = smooth;
}

QCustomPlot之平滑曲线上(八)相关推荐

  1. [资源分享] Github上八千Star的深度学习500问教程

    本文大约 600 字,阅读大约需要 2 分钟 这周要分享的一个资源是来自 Github 上的已经有八千多 Star 的一个深度学习知识总结,如下图所示: 其 Github 地址为: https://g ...

  2. foxmail提示不知道这样的主机_开车上八楼停车场,坡道拐弯会车要这样做,知道了不吃亏...

    今天我开车带大家去体验一个设置在八楼楼顶的停车场,看一下开车如何爬楼,开车上下楼又有哪些技巧和注意事项. 这是停车场的出入口,左边是出口,右边是进口,上方提示限速5公里,限高2米. 慢行进入停车场进口 ...

  3. 风水学上八种住宅要避忌

    "宅以形势为身体,以泉水为血脉,以土地为皮肉,以草木为毛发,以舍屋为衣服,以门户为冠带.若是如斯,是事俨雅,乃为上吉."这是古人把住宅人性化,说明格局搭配得当,对住宅与人都是很重要 ...

  4. 主板h110能装linux吗_H110冒充H310 老主板居然也能上八代酷睿

    近日据网友爆料,有主板厂商拿老的H110芯片组冒充最新的H310,居然可以同时支持6.7.8三代酷睿处理器.同时网友还给出了证据,证明两款被曝光的"老酒装新瓶"的H310主板就是H ...

  5. stm32简明教程系列(二)----GPIO(上)八种模式的区别与应用场合

    一.概述 GPIO全称为通用输入/输出端口.是stm32用于输出信号,输入信号的通道.他有以下八种模式: 输入方式 浮空输入 GPIO_Mode_IN_FLOATING 上拉GPIO_Mode_IPU ...

  6. iphonex正面图_【苹果iPhoneX评测】刘海上八个模块各显神通_苹果 iPhone X _手机评测-中关村在线...

    ▌1.红外镜头 刘海上第一个就是红外镜头,这是此次iPhoneX上才添加的模块,专为面部识别Face ID而生.红外镜头可以通过捕获红外图像中人脸上的点阵图案来和A11仿生SoC中Secure Enc ...

  7. QCustomPlot基础教程(八)——QCustomPlot将绘制的图形保存导出

    目录 一.函数介绍 二.代码示例 一.函数介绍 QCustomPlot提供了四种常用的save接口,其格式如下: saveBmp(const QString &fileName, int wi ...

  8. 历数史上八次1比3翻盘好戏

    体坛网讯 虽然骑士在本场比赛以1比3落后,但是也并非绝无生机.纵观历史数据,在系列赛中以3-1领先的情况下,领先的一方有95%的几率取得系列赛的胜利.但是联盟里也有8支球队在如此的情况下仍然发生被翻盘 ...

  9. 项目经理的超越(三)人际优先,做事上的超越

    韩非子曾经讲过一个寓言--智子疑邻. -------------------------------------------------------- 宋国有一个富人,天下大雨,他家的墙坏了. 富人的 ...

最新文章

  1. C++高斯赛德迭代法,求线性方程组的解(version1.0)
  2. android excel 筛选功能,Android实现Excel表格展示数据
  3. CityEngine生成不等间距桥墩
  4. 《此生未完成》痛句摘抄(3)
  5. Pandas 读写数据
  6. 编译在arm版本的Valgrind-转
  7. to load JavaHL Library解决方法
  8. springboot实现热部署,修改代码不用重启服务
  9. 凸集、凸函数、凸优化和凸二次规划
  10. HTTP报文结构详解
  11. 江苏省计算机二级c语言备考,江苏省计算机二级C语言考试备考指南
  12. shell机器人企业微信通知
  13. C++ 创建桌面快捷方式
  14. 外汇短线交易者的规则
  15. Win10 Outlook打不开,无法启动Microsoft Outlook。无法打开Outlook窗口。无法打开此文件夹集合。客户端操作失败
  16. 常用的数学符号sup(上确界) 和 inf(下确界)以及少量数学公式的markdown模式下latex 格式 编写
  17. windows点阵字体转linux版,Deepin 20.1下安装和配置点阵字体,可解决低分屏字体模糊问题...
  18. 《空号》:聊聊我在阿里外包3个月学到了什么。。。
  19. 蓝牙血压计医疗方案设计
  20. deepin linux软件,深度软件包安装器

热门文章

  1. 思科 CCNA2 第六章测验答案
  2. Word Embedding与analogy reasoning(词嵌入与类比推理的过程)
  3. 874. 筛法求欧拉函数
  4. 刷脸支付是一个颠覆支付行业的全新革命
  5. Springboot橘子酒店管理系统eg48i计算机毕业设计-课程设计-期末作业-毕设程序代做
  6. p1口流水灯c语言,单片机实验二--P1口输出实验(流水灯)
  7. 2022-2028年中国消防机器人行业市场前瞻与投资战略规划分析报告
  8. AE平面跟踪和视觉效果插件mocha pro mac破解版
  9. 【Java 行为型设计模式 IV】观察者模式、中介模式详解
  10. linux7zip,Centos7中使用7zip压缩工具