337 lines
11 KiB
C++
337 lines
11 KiB
C++
#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();
|
||
}
|
||
}
|