使用qcustomplot绘制贝塞尔平滑曲线

之前需要绘制平滑曲线,使用qcharts 绘制 效果不错,但是我的曲线数量较多,跑在板子上会出现明显卡顿,所以使用qcustomplot 。但是qcustomplot没有平滑曲线的绘制方法,最终找到了这篇文章,QCustomPlot之平滑曲线
关于修改后的错误:QVector lineData(QVector(points.constBegin() + segmentStart, points.constBegin() + i - segmentStart));
果然我很菜,问了版主,已解决

QVector<QPointF> lineData(i - segmentStart); 
std::copy(points.constBegin() + segmentStart, points.constBegin() + i - segmentStart, lineData.begin());

可以绘制平滑曲线的文件我已修改好:qcustomplot.zip
在这里插入图片描述
放大
在这里插入图片描述

以下转载:


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

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

一、生成平滑曲线

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

作者:lowbees
链接:https://www.jianshu.com/p/0d4b84bd611a
来源:简书

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的线风格mLineStyle为lsLine的时候才会真正的绘制平滑曲线

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;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部