EnergySpectrumAnalyer/src/CountRateAnalysisView/CountRateAnalysisView.cpp

337 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CountRateAnalysisView.h"
#include "ui_CountRateAnalysisView.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QMessageBox>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QColorDialog>
#include <QMap>
#include <QwtPlotCurve>
#include <QwtPlotMarker>
#include <QwtPlotZoneItem>
#include <QwtPlotCanvas>
#include <QwtLegend>
#include <QwtText>
#include <cmath>
#include <QtMath>
#include "CustomQwtPlot.h"
#include <QDebug>
#include <GlobalDefine.h>
#include "csv.h"
#include <QThread>
#include "BusyIndicator.h"
#include <QMenu>
CountRateAnalysisView::CountRateAnalysisView(QWidget *parent) :
MeasureAnalysisView(parent),
ui(new Ui::CountRateAnalysisView)
{
ui->setupUi(this);
this->setViewType(PlotFrame);
this->_menu = new QMenu(this);
_busy_indicator = new BusyIndicatorWidget(this);
InitUi();
setupMenu();
}
CountRateAnalysisView::~CountRateAnalysisView()
{
delete ui;
}
void CountRateAnalysisView::InitViewWorkspace(const QString &project_name)
{
}
void CountRateAnalysisView::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
{
if(!data_files_set.isEmpty()) {
_busy_indicator->Start();
auto functionToRun = [this,data_files_set] {
QVector<ParticleInjectTime> data = getParticleInjectTimeData(data_files_set.first().toString());
QMetaObject::invokeMethod(this, [this, data]() {
setData(data);
_busy_indicator->Stop();
}, Qt::QueuedConnection);
};
QThread* load_data_thread = QThread::create(functionToRun);
load_data_thread->start();
}
}
void CountRateAnalysisView::showEvent(QShowEvent *e)
{
Q_UNUSED(e);
if (_busy_indicator) {
_busy_indicator->setGeometry(this->rect());
this->update();
}
}
void CountRateAnalysisView::setData(QVector<ParticleInjectTime> data)
{
int energyStart = ui->label_energyStart->text().toInt();
int energyEnd = ui->label_energyEnd->text().toInt();
int nInv = 1;
constexpr qint64 NS_PER_SECOND = 1000000000; // 纳秒转秒的基数
if (data.isEmpty()) return; // 添加空列表保护
QVector<double> x;
QVector<double> y;
const ParticleInjectTime& lostdt = data.last();
const qint64 totalNanoseconds = lostdt.dTime * 5;
const int nAllS = static_cast<int>(totalNanoseconds / NS_PER_SECOND) + 1;
const int nVecSize = nAllS / nInv;
QVector<double> vec(nVecSize); // 默认初始化为0
double x_max = 0;
double y_max = 0;
for(auto info : data) {
const qint64 ns = (info.dTime * 5) / NS_PER_SECOND;
const int nidx = static_cast<int>(ns / nInv); // 整数除法,速度快
if (nidx < nVecSize) {
++vec[nidx];
if ( y_max < vec[nidx] )
y_max = vec[nidx];
}
}
QVector<double> vecXpt(vec.size());
for (int i = 0; i < vec.size(); ++i) {
vecXpt[i] = static_cast<double>(i);
if ( x_max < vecXpt[i] )
x_max = vecXpt[i];
}
plot->SetAxisInitRange(QwtPlot::xBottom, 0.0f, x_max);
plot->SetAxisInitRange(QwtPlot::yLeft, 0.0f, y_max);
// 创建曲线并设置数据
QwtPlotCurve *curve = new QwtPlotCurve();
curve->setSamples(vecXpt, vec);
// 将曲线添加到 CustomQwtPlot 中(会自动分配颜色)
plot->AddCurve(curve);
// 设置坐标轴范围和标题
// plot->setAxisScale(QwtPlot::xBottom, 0, x.last());
// plot->setAxisScale(QwtPlot::yLeft,minValue , maxValue);
// LOG_INFO(QStringLiteral(u"[%1]计数率分析数据读取完毕.").arg(this->GetProjectName()).arg(this->GetViewName()));
// 刷新绘图
plot->replot();
}
QVector<ParticleInjectTime> CountRateAnalysisView::getParticleInjectTimeData(QString path)
{
QVector<ParticleInjectTime> records;
io::CSVReader<4> in(QStrToSysPath(path));
in.read_header(io::ignore_extra_column, "板卡号", "通道号", "能量(KeV)", "时间计数");
int board, channel;
double energy, time_count;
int lineNumber = 0;
// 逐行读取
while (in.read_row(board, channel, energy, time_count))
{
int detector = board + channel * 8;
lineNumber++;
if(detector >= 32)
{
continue;
}
ParticleInjectTime rec;
rec.index = lineNumber;
rec.dEnergy = energy;
rec.dTime = time_count;
records.append(rec);
}
return records;
}
void CountRateAnalysisView::InitUi()
{
plot = new CustomQwtPlot();
setupPlot();
ui->verticalLayout_2->addWidget(plot);
}
void CountRateAnalysisView::setupPlot()
{
plot->setCanvasBackground(Qt::white);
QwtPlotCanvas* canvas = qobject_cast<QwtPlotCanvas*>(plot->canvas());
canvas->setFrameStyle(QFrame::NoFrame);
plot->setAxisTitle(QwtPlot::xBottom, QStringLiteral(u"时间"));
plot->setAxisTitle(QwtPlot::yLeft, QStringLiteral(u"计数"));
// set axis auto scale
plot->setAxisAutoScale(QwtPlot::xBottom, true);
plot->setAxisAutoScale(QwtPlot::yLeft, true);
// 启用网格线
plot->enableAxis(QwtPlot::xBottom);
plot->enableAxis(QwtPlot::yLeft);
// 设置QWT图例
// QwtLegend* legend = new QwtLegend();
// legend->setDefaultItemMode(QwtLegendData::ReadOnly);
// plot->insertLegend(legend, QwtPlot::RightLegend);
plot->SetAxisDragScale(QwtPlot::xBottom, true);
}
void CountRateAnalysisView::setupMenu()
{
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &CountRateAnalysisView::customContextMenuRequested, [this](const QPoint& pos) {
this->_menu->exec(this->mapToGlobal(pos));
});
QAction* action_plot_reset = this->_menu->addAction(QStringLiteral(u"还原"));
action_plot_reset->setObjectName("plot_reset");
connect(action_plot_reset, &QAction::triggered, [this]() {
this->plot->ResetPlot();
});
this->_menu->addSeparator();
QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置"));
action_plot_config->setObjectName("plot_config");
connect(action_plot_config, &QAction::triggered, this, &CountRateAnalysisView::onActionPlotConfigure);
}
void CountRateAnalysisView::onActionPlotConfigure()
{
QDialog dlg(this);
dlg.setWindowTitle(QStringLiteral(u"图表配置"));
dlg.setMinimumWidth(320);
QVBoxLayout* layout = new QVBoxLayout(&dlg);
// X轴标题
QHBoxLayout* xTitleLayout = new QHBoxLayout();
QLabel* xTitleLabel = new QLabel(QStringLiteral(u"X轴标题"), &dlg);
QLineEdit* xTitleEdit = new QLineEdit(plot->axisTitle(QwtPlot::xBottom).text(), &dlg);
xTitleLayout->addWidget(xTitleLabel);
xTitleLayout->addWidget(xTitleEdit);
layout->addLayout(xTitleLayout);
// Y轴标题
QHBoxLayout* yTitleLayout = new QHBoxLayout();
QLabel* yTitleLabel = new QLabel(QStringLiteral(u"Y轴标题"), &dlg);
QLineEdit* yTitleEdit = new QLineEdit(plot->axisTitle(QwtPlot::yLeft).text(), &dlg);
yTitleLayout->addWidget(yTitleLabel);
yTitleLayout->addWidget(yTitleEdit);
layout->addLayout(yTitleLayout);
layout->addSpacing(8);
// 显示网格
QCheckBox* gridCheck = new QCheckBox(QStringLiteral(u"显示网格线"), &dlg);
gridCheck->setChecked(plot->axisEnabled(QwtPlot::xBottom) && plot->axisEnabled(QwtPlot::yLeft));
layout->addWidget(gridCheck);
// 显示图例
QCheckBox* legendCheck = new QCheckBox(QStringLiteral(u"显示图例"), &dlg);
legendCheck->setChecked(plot->legend() != nullptr);
layout->addWidget(legendCheck);
layout->addSpacing(8);
// 曲线颜色
QLabel* curveColorLabel = new QLabel(QStringLiteral(u"曲线颜色:"), &dlg);
layout->addWidget(curveColorLabel);
// 获取所有曲线
QList<QwtPlotCurve*> curveList;
QMap<QwtPlotCurve*, QColor> curveColorMap;
const QwtPlotItemList& items = plot->itemList();
for (QwtPlotItem* item : items) {
if (item->rtti() == QwtPlotItem::Rtti_PlotCurve) {
QwtPlotCurve* curve = static_cast<QwtPlotCurve*>(item);
curveList.append(curve);
curveColorMap.insert(curve, curve->pen().color());
}
}
// 为每条曲线创建颜色按钮
QList<QPushButton*> colorBtnList;
for (int i = 0; i < curveList.size(); ++i) {
QwtPlotCurve* curve = curveList.at(i);
QHBoxLayout* btnLayout = new QHBoxLayout();
QLabel* nameLabel = new QLabel(QStringLiteral(u"曲线%1").arg(i + 1), &dlg);
QPushButton* colorBtn = new QPushButton(&dlg);
colorBtn->setFixedSize(60, 24);
QColor color = curveColorMap.value(curve);
colorBtn->setStyleSheet(QString("background-color: %1; border: 1px solid #999;")
.arg(color.name()));
btnLayout->addWidget(nameLabel);
btnLayout->addWidget(colorBtn);
btnLayout->addStretch();
layout->addLayout(btnLayout);
colorBtnList.append(colorBtn);
connect(colorBtn, &QPushButton::clicked, [&dlg, curve, &curveColorMap, colorBtn]() {
QColor current = curveColorMap.value(curve);
QColor selected = QColorDialog::getColor(current, &dlg, QStringLiteral(u"选择曲线颜色"));
if (selected.isValid()) {
curveColorMap[curve] = selected;
colorBtn->setStyleSheet(QString("background-color: %1; border: 1px solid #999;")
.arg(selected.name()));
}
});
}
layout->addStretch();
// 确定取消按钮
QDialogButtonBox* buttonBox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dlg);
layout->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
if (dlg.exec() == QDialog::Accepted) {
// 应用X轴标题
plot->setAxisTitle(QwtPlot::xBottom, xTitleEdit->text());
// 应用Y轴标题
plot->setAxisTitle(QwtPlot::yLeft, yTitleEdit->text());
// 应用网格显示
plot->enableAxis(QwtPlot::xBottom, gridCheck->isChecked());
plot->enableAxis(QwtPlot::yLeft, gridCheck->isChecked());
// 应用图例显示
if (legendCheck->isChecked() && plot->legend() == nullptr) {
QwtLegend* legend = new QwtLegend();
legend->setDefaultItemMode(QwtLegendData::ReadOnly);
plot->insertLegend(legend, QwtPlot::RightLegend);
// 给未命名曲线设置默认标题,保证图例显示名称
int idx = 1;
const QwtPlotItemList& items = plot->itemList();
for (QwtPlotItem* item : items) {
if (item->rtti() == QwtPlotItem::Rtti_PlotCurve) {
QwtPlotCurve* curve = static_cast<QwtPlotCurve*>(item);
if (curve->title().isEmpty()) {
curve->setTitle(QStringLiteral(u"曲线%1").arg(idx));
}
++idx;
}
}
} else if (!legendCheck->isChecked() && plot->legend() != nullptr) {
plot->insertLegend(nullptr);
}
// 应用曲线颜色
for (QwtPlotCurve* curve : curveList) {
QPen pen = curve->pen();
pen.setColor(curveColorMap.value(curve));
curve->setPen(pen);
}
// 刷新绘图
plot->replot();
}
}