You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++/QCustomPlot散点图技术问题:多向量排序与边界绘制

解决QCustomPlot绘制散点图外边界的问题

嘿,刚好我之前做过类似的需求,给你一个简单可行的方案——通过计算点集的凸包来绘制外边界,这样就能得到近似圆形的轮廓,完全符合你要的效果!

步骤详解:

  1. 筛选有效点
    首先把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]);
        }
    }
    
  2. 计算凸包
    凸包是能包围所有点的最小凸多边形,用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;
    }
    
  3. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:28:18