C++/QCustomPlot散点图技术问题:多向量排序与边界绘制
解决QCustomPlot绘制散点图外边界的问题
嘿,刚好我之前做过类似的需求,给你一个简单可行的方案——通过计算点集的凸包来绘制外边界,这样就能得到近似圆形的轮廓,完全符合你要的效果!
步骤详解:
筛选有效点
首先把hits标记为命中的点(假设命中值为1)从x、y向量中提取出来,组成点集:std::vector<QPointF> hitPoints; for (size_t i = 0; i < x.size(); ++i) { if (hits[i] == 1) { // 根据你的实际命中标记调整这里 hitPoints.emplace_back(x[i], y[i]); } }计算凸包
凸包是能包围所有点的最小凸多边形,用Andrew算法实现起来简单高效,代码如下:// 辅助函数:计算叉积,判断三点的转向 double cross(const QPointF& a, const QPointF& b, const QPointF& c) { return (b.x() - a.x())*(c.y() - a.y()) - (b.y() - a.y())*(c.x() - a.x()); } // 计算点集的凸包 std::vector<QPointF> computeConvexHull(std::vector<QPointF> points) { if (points.size() <= 1) return points; // 按x坐标排序,x相同则按y排序 std::sort(points.begin(), points.end(), [](const QPointF& a, const QPointF& b) { return a.x() < b.x() || (a.x() == b.x() && a.y() < b.y()); }); std::vector<QPointF> lower, upper; // 构建下凸包 for (const auto& p : points) { while (lower.size() >= 2 && cross(lower[lower.size()-2], lower.back(), p) <= 0) { lower.pop_back(); } lower.push_back(p); } // 构建上凸包 for (auto it = points.rbegin(); it != points.rend(); ++it) { const auto& p = *it; while (upper.size() >= 2 && cross(upper[upper.size()-2], upper.back(), p) <= 0) { upper.pop_back(); } upper.push_back(p); } // 合并凸包,去掉重复的首尾点 lower.pop_back(); upper.pop_back(); lower.insert(lower.end(), upper.begin(), upper.end()); return lower; }在QCustomPlot中绘制凸包边界
把计算得到的凸包点设置到QCPGraph中,只显示线条不显示散点,就能得到清晰的外边界了:// 假设这是你的QCustomPlot实例 QCustomPlot* plot = ui->customPlot; auto convexHull = computeConvexHull(hitPoints); // 创建用于绘制边界的曲线 QCPGraph* hullGraph = plot->addGraph(); QVector<double> hullX, hullY; for (const auto& p : convexHull) { hullX.append(p.x()); hullY.append(p.y()); } // 闭合边界:把第一个点添加到末尾 if (!convexHull.empty()) { hullX.append(convexHull.first().x()); hullY.append(convexHull.first().y()); } // 设置曲线样式 hullGraph->setData(hullX, hullY); hullGraph->setPen(QPen(Qt::darkRed, 2)); // 线条颜色和粗细可以自行调整 hullGraph->setScatterStyle(QCPScatterStyle::ssNone); // 不显示散点,只留边界 // 刷新绘图 plot->replot();
补充说明:
- 如果你的命中标记不是
1,只需要修改第一步的判断条件即可; - 只要原始点集近似圆形,凸包的轮廓会非常接近圆形,完全满足你的需求;
- 如果点太少(比如少于3个),凸包可能无法形成闭合边界,你可以根据实际情况添加判断处理。
内容的提问来源于stack exchange,提问作者John Shearer
相关产品推荐
相关产品推荐

