本小节内容致力于解决,qcustomplot无法绘制曲线的问题,在修改源码之后,可以在绘图过程中增加曲线的绘制。 参考博文连接
曲线绘制的移植
1、添加如下代码到qcustomplot.c 中
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());
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(i - segmentStart); std::copy(points.constBegin() + segmentStart, points.constBegin() + i - segmentStart, lineData.begin());
result.addPath(generateSmoothCurveImp(lineData));
segmentStart = i + 1;
}
++i;
}
QVector<QPointF> lineData(i - segmentStart); std::copy(points.constBegin() + segmentStart, points.constBegin() + i - segmentStart, lineData.begin());
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;
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;
}
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) {
(*firstControlPoints)[0].rx() = (2 * knots[0].x() + knots[1].x()) / 3;
(*firstControlPoints)[0].ry() = (2 * knots[0].y() + knots[1].y()) / 3;
(*secondControlPoints)[0].rx() = 2 * (*firstControlPoints)[0].x() - knots[0].x();
(*secondControlPoints)[0].ry() = 2 * (*firstControlPoints)[0].y() - knots[0].y();
return;
}
double *xs = nullptr;
double *ys = nullptr;
double *rhsx = new double[n];
double *rhsy = new double[n];
for (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;
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 * 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;
}
};
2、再对在qcustomplot.c 的void QCPGraph::drawLinePlot(QCPPainter *painter, const QVector<QPointF> &lines) const 函数进行复制替换
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);
}
}
3、在class QCP_LIB_DECL QCPGraph : public QCPAbstractPlottable1D<QCPGraphData> 函数中添加公共类和保护类成员。
class QCP_LIB_DECL QCPGraph : public QCPAbstractPlottable1D<QCPGraphData>
{
public:
void setSmooth(bool smooth);
protected:
bool mSmooth;
}
4、在qcustomplot.c 其他地方添加如下函数
void QCPGraph::setSmooth(bool smooth)
{
mSmooth = smooth;
}
结果展示
完成以上四步骤就可以使用平滑曲线的绘制。
在绘制曲线中着重添加如下的函数:
customPlot->replot(QCustomPlot::rpQueuedReplot);
customPlot->graph(1)->setSmooth(true);
实际效果如下图所示:图中的点都是rand() 随机数 再对比一下改版之前的结果 效果十分显著,这样就已经实现了平滑曲线的绘制。
|