如何根据X坐标获取QWT绘图曲线的Y坐标?
解决QwtPlotCurve根据X坐标精确获取Y值的问题
嘿,我太懂你现在的困扰了——用closestPoint()只能拿到离目标X最近的那个采样点,要是你的曲线是插值绘制的(比如线性、样条平滑),这个结果精度肯定不够对吧?别慌,咱们直接用Qwt自带的工具就能搞定精确插值的需求,下面一步步来:
步骤1:把屏幕坐标转成绘图数据坐标
首先得把鼠标事件的全局坐标,转换成绘图区里的实际数据X值,这一步靠QwtScaleMap来完成:
// 先把全局坐标转成画布上的坐标 QPoint canvasPos = plotCanvas->mapFromGlobal(event->pos()); // 获取X轴和Y轴的坐标映射 QwtScaleMap xMap = curve->plot()->canvasMap(QwtPlot::xBottom); QwtScaleMap yMap = curve->plot()->canvasMap(QwtPlot::yLeft); // 把屏幕X坐标转成数据里的目标X值 double targetX = xMap.invTransform(canvasPos.x());
步骤2:找到目标X所在的相邻采样点
Qwt的采样点是离散的,咱们得先找到目标X夹在哪两个采样点之间。这里分两种情况:
普通遍历(适合采样点不多的情况)
const QVector<QPointF>& samples = curve->samples(); int sampleCount = samples.size(); // 采样点太少的边界处理 if (sampleCount < 2) { if (sampleCount == 1) return samples.first().y(); return 0; // 或者根据你的需求返回默认值 } int leftIndex = 0; // 找到第一个X大于targetX的点,它的前一个就是左邻居 for (; leftIndex < sampleCount - 1; ++leftIndex) { if (samples[leftIndex + 1].x() > targetX) { break; } } int rightIndex = leftIndex + 1;
二分查找优化(适合大量采样点)
如果你的曲线有几百上千个采样点,遍历效率太低,用二分查找更快(前提是采样点按X升序排列,Qwt默认是排序的):
const QVector<QPointF>& samples = curve->samples(); int sampleCount = samples.size(); if (sampleCount < 2) { if (sampleCount == 1) return samples.first().y(); return 0; } int left = 0, right = sampleCount - 1; while (right - left > 1) { int mid = (left + right) / 2; if (samples[mid].x() < targetX) { left = mid; } else { right = mid; } } // 循环结束后,left和right就是相邻的两个点(或边界点) int leftIndex = left; int rightIndex = right;
步骤3:根据曲线插值方式计算精确Y值
接下来就看你的曲线用的是什么插值方式了:
线性插值(Qwt默认)
如果你的曲线是线性绘制的,直接用线性插值公式就行:
QPointF leftPoint = samples[leftIndex]; QPointF rightPoint = samples[rightIndex]; // 计算斜率,然后代入插值公式 double slope = (rightPoint.y() - leftPoint.y()) / (rightPoint.x() - leftPoint.x()); double preciseY = leftPoint.y() + slope * (targetX - leftPoint.x());
样条插值(平滑曲线)
如果你的曲线开启了样条拟合(比如设置了curve->setCurveAttribute(QwtPlotCurve::Fitted, true)),那就用QwtSpline来计算,精度更高:
QwtSpline spline; // 自动适配样条类型,也可以指定比如QwtSpline::NaturalSpline spline.setFitMode(QwtSpline::Auto); spline.setPoints(samples); // 直接获取目标X对应的插值Y值 double preciseY = spline.value(targetX);
几个重要的注意事项
- 确保采样点是按X坐标升序排列的:如果是自己手动添加的采样点,记得先排序,不然找邻居的逻辑会出错。可以用
curve->setCurveAttribute(QwtPlotCurve::Sorted, true)让Qwt自动排序。 - 处理边界情况:如果目标X比所有采样点的X都小,就用第一个点的Y;比所有都大,就用最后一个点的Y。
- 多段曲线的情况:如果你的曲线是断开的(比如有多个不连续的段),需要先判断目标X落在哪个段里,再进行插值。
这样替换掉原来用closestPoint()取采样点的方式,就能得到和绘图曲线完全匹配的精确Y值了!
内容的提问来源于stack exchange,提问作者Nikita
相关产品推荐
相关产品推荐

