From 6ff3e185ca98ba3ec1b29aaff5839285ca865014 Mon Sep 17 00:00:00 2001 From: anxinglong <2910824064@qq.com> Date: Tue, 12 May 2026 20:52:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B8=E7=B4=A0=E5=88=86?= =?UTF-8?q?=E6=9E=90=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CoincidenceEventTimeView.cpp | 31 +++- .../CoincidenceEventTimeView.h | 7 +- .../ConformToTheEnergySpectrum.cpp | 32 ++-- .../EnergyCountPeakFitView.cpp | 22 +-- src/EnergyCountPeakFitView/PlotRectItem.cpp | 5 +- src/MeasureAnalysisTreeView.cpp | 9 ++ src/MeasureAnalysisView.cpp | 6 +- .../NuclideAnalysisView.cpp | 138 ++++++++++++++++++ src/NuclideAnalysisView/NuclideAnalysisView.h | 33 +++++ src/src.pro | 15 +- 10 files changed, 259 insertions(+), 39 deletions(-) create mode 100644 src/NuclideAnalysisView/NuclideAnalysisView.cpp create mode 100644 src/NuclideAnalysisView/NuclideAnalysisView.h diff --git a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp index 637cd56..65bdec0 100644 --- a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp +++ b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp @@ -32,7 +32,8 @@ CoincidenceEventTimeView::CoincidenceEventTimeView(QWidget *parent) : _plot = new CustomQwtPlot(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(_plot); - + this->_menu = new QMenu(this); + setupMenu(); _plot->setCanvasBackground(Qt::white); QwtPlotCanvas* canvas = qobject_cast(_plot->canvas()); canvas->setFrameStyle(QFrame::NoFrame); @@ -166,9 +167,8 @@ void CoincidenceEventTimeView::loadAndProcess() QMetaObject::invokeMethod(this, [this, vx, vy, dmaxx, dmaxy]() { _curve->setSamples(vx, vy); - - _plot->setAxisScale(QwtPlot::xBottom, 0, dmaxx); - _plot->setAxisScale(QwtPlot::yLeft, 0, dmaxy * 1.1); + _plot->SetAxisInitRange(QwtPlot::yLeft,0.0f, dmaxy); + _plot->SetAxisInitRange(QwtPlot::xBottom,0.0f, dmaxx); _plot->replot(); _busy_indicator->Stop(); }, Qt::QueuedConnection); @@ -188,4 +188,27 @@ void CoincidenceEventTimeView::showEvent(QShowEvent *e) } } +void CoincidenceEventTimeView::setupMenu() +{ + this->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &CoincidenceEventTimeView::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, &CoincidenceEventTimeView::onActionPlotConfigure); + this->_menu->addSeparator(); +} + +void CoincidenceEventTimeView::onActionPlotConfigure() +{ + +} + diff --git a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h index 968a609..75de489 100644 --- a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h +++ b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h @@ -2,7 +2,7 @@ #define COINCIDENCEEVENTTIMEVIEW_H #include "MeasureAnalysisView.h" - +#include class CustomQwtPlot; class QwtPlotCurve; class BusyIndicator; @@ -21,12 +21,15 @@ protected: private: void loadAndProcess(); // 读取CSV,执行符合处理,绘制能谱折线图 - + void setupMenu(); +private slots: + void onActionPlotConfigure(); private: BusyIndicator* _busy_indicator = nullptr; CustomQwtPlot* _plot = nullptr; QwtPlotCurve* _curve = nullptr; QStringList _data_filenames; + QMenu* _menu = nullptr; }; #endif // COINCIDENCEEVENTTIMEVIEW_H diff --git a/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp b/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp index ebd9571..4ff3092 100644 --- a/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp +++ b/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp @@ -110,25 +110,25 @@ void ConformToTheEnergySpectrum::loadAndProcess() return; } -// const uint64_t TIME_WINDOW_NS = 50; -// const int MIN_ORDER = 2; -// const int MAX_ORDER = 9; -// std::vector coincidences = processCoincidence(rawData, TIME_WINDOW_NS, MIN_ORDER, MAX_ORDER); + // const uint64_t TIME_WINDOW_NS = 50; + // const int MIN_ORDER = 2; + // const int MAX_ORDER = 9; + // std::vector coincidences = processCoincidence(rawData, TIME_WINDOW_NS, MIN_ORDER, MAX_ORDER); -// if (coincidences.empty()) { -// _busy_indicator->Stop(); -// return; -// } + // if (coincidences.empty()) { + // _busy_indicator->Stop(); + // return; + // } -// const int STEP = 1; -// std::map hist; + // const int STEP = 1; + // std::map hist; -// for (const auto& ev : coincidences) { -// for (const auto& spdt : ev.events) { -// int idx = static_cast(spdt.energy) / STEP; -// hist[idx] += 1.0; -// } -// } + // for (const auto& ev : coincidences) { + // for (const auto& spdt : ev.events) { + // int idx = static_cast(spdt.energy) / STEP; + // hist[idx] += 1.0; + // } + // } const int STEP = 1; std::map hist; diff --git a/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp b/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp index b93772b..5e358dc 100644 --- a/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp +++ b/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp @@ -224,9 +224,9 @@ void EnergyCountPeakFitView::setupMenu() this->_plot->ResetPlot(); }); this->_menu->addSeparator(); - QAction* action_set_curve_show = this->_menu->addAction(QStringLiteral(u"选择曲线")); - action_set_curve_show->setObjectName("curve_show_setting"); - connect(action_set_curve_show, &QAction::triggered, this, &EnergyCountPeakFitView::onActionCurveShowSetting); + //QAction* action_set_curve_show = this->_menu->addAction(QStringLiteral(u"选择曲线")); + //action_set_curve_show->setObjectName("curve_show_setting"); + //connect(action_set_curve_show, &QAction::triggered, this, &EnergyCountPeakFitView::onActionCurveShowSetting); QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置")); action_plot_config->setObjectName("plot_config"); connect(action_plot_config, &QAction::triggered, this, &EnergyCountPeakFitView::onActionPlotConfigure); @@ -234,8 +234,8 @@ void EnergyCountPeakFitView::setupMenu() this->_menu->addSeparator(); QAction* action_refit_rect = this->_menu->addAction(QStringLiteral(u"重新拟合当前区域")); connect(action_refit_rect, &QAction::triggered, this, &EnergyCountPeakFitView::onActionRefitCurrentRect); - QAction* action_save_fit = this->_menu->addAction(QStringLiteral(u"保存当前拟合结果")); - connect(action_save_fit, &QAction::triggered, this, &EnergyCountPeakFitView::onActionSaveCurrentFit); + //QAction* action_save_fit = this->_menu->addAction(QStringLiteral(u"保存当前拟合结果")); + //connect(action_save_fit, &QAction::triggered, this, &EnergyCountPeakFitView::onActionSaveCurrentFit); QAction* action_show_history = this->_menu->addAction(QStringLiteral(u"峰拟合结果")); connect(action_show_history, &QAction::triggered, this, &EnergyCountPeakFitView::onActionShowFitHistory); @@ -243,8 +243,8 @@ void EnergyCountPeakFitView::setupMenu() QAction* action_delete_hovered_rect = this->_menu->addAction(QStringLiteral(u"删除当前框选区域")); connect(action_delete_hovered_rect, &QAction::triggered, this, &EnergyCountPeakFitView::onActionDeleteHoveredRect); - QAction* action_hint = this->_menu->addAction(QStringLiteral(u"框选提示:按住 Ctrl 键并拖动左键")); - action_hint->setEnabled(false); + //QAction* action_hint = this->_menu->addAction(QStringLiteral(u"框选提示:按住 Ctrl 键并拖动左键")); + //action_hint->setEnabled(false); } void EnergyCountPeakFitView::loadDataFromFile(const QString& data_name, const QString& filename) @@ -381,8 +381,8 @@ bool EnergyCountPeakFitView::eventFilter(QObject* watched, QEvent* event) // 按下 Ctrl+左键 开始框选 if (event->type() == QEvent::MouseButtonPress && - me->button() == Qt::LeftButton && - (me->modifiers() & Qt::ControlModifier)) { + me->button() == Qt::LeftButton /*&&*/ + /*(me->modifiers() & Qt::ControlModifier)*/) { startSelection(me->pos()); return true; @@ -476,7 +476,7 @@ void EnergyCountPeakFitView::finishSelection() if (roiX.size() >= 3) { QStringList algorithms; - algorithms << QStringLiteral(u"光子峰拟合算法"); + algorithms << QStringLiteral(u"y=A*exp(-pow(x-P,2)/(2*pow(delt,2))) + H/(1+exp((x-P)/W)) + C"); bool ok = false; QString selected = QInputDialog::getItem(this, QStringLiteral(u"选择拟合算法"), @@ -485,7 +485,7 @@ void EnergyCountPeakFitView::finishSelection() 0, false, &ok); - if (ok && selected == QStringLiteral(u"光子峰拟合算法")) + if (ok && selected == QStringLiteral(u"y=A*exp(-pow(x-P,2)/(2*pow(delt,2))) + H/(1+exp((x-P)/W)) + C")) { arma::vec armaRoiX(roiX.size()), armaRoiY(roiY.size()); for (int i = 0; i < roiX.size(); ++i) { diff --git a/src/EnergyCountPeakFitView/PlotRectItem.cpp b/src/EnergyCountPeakFitView/PlotRectItem.cpp index ac32b93..41f645c 100644 --- a/src/EnergyCountPeakFitView/PlotRectItem.cpp +++ b/src/EnergyCountPeakFitView/PlotRectItem.cpp @@ -82,7 +82,8 @@ void PlotRectItem::draw(QPainter *painter, painter->setRenderHint(QPainter::TextAntialiasing); // 构建文本内容 - QString text = QString("峰位: %1 keV\n" + QString text = QString( + "峰位: %1 keV\n" "FWHM: %2\n" "面积: %3\n" "本底: %4") @@ -92,7 +93,7 @@ void PlotRectItem::draw(QPainter *painter, .arg(m_baseline, 0, 'f', 2); // 计算文本位置:矩形右上角 + 偏移量 - QPoint textPos(x2 + 10, y2); + QPoint textPos(x2 + 20, y2 + 10); // 绘制半透明背景框(增强可读性) QFont font = painter->font(); diff --git a/src/MeasureAnalysisTreeView.cpp b/src/MeasureAnalysisTreeView.cpp index fa1d94d..d4a9084 100644 --- a/src/MeasureAnalysisTreeView.cpp +++ b/src/MeasureAnalysisTreeView.cpp @@ -285,6 +285,15 @@ void MeasureAnalysisTreeView::onNodeDoubleClicked(const QModelIndex& index) } } } break; + case AnalysisType::NuclideAnalysisView: { + MeasureAnalysisProjectModel* project_model = _model->GetProjectModel(project_name); + if (project_model) { + auto all_ch_energy_count_file_name = project_model->GetAllChannelEnergyTotalCountDataFilename(); + if (!all_ch_energy_count_file_name.isEmpty()) { + data_files_set[QStringLiteral(u"核素分析")] = all_ch_energy_count_file_name; + } + } + } break; default: break; } diff --git a/src/MeasureAnalysisView.cpp b/src/MeasureAnalysisView.cpp index c1a60c6..b31a05e 100644 --- a/src/MeasureAnalysisView.cpp +++ b/src/MeasureAnalysisView.cpp @@ -12,6 +12,7 @@ #include "ConformToTheEnergySpectrum.h" #include "AntiConformEnergySpectrumView.h" #include "CoincidenceEventTimeView.h" +#include "NuclideAnalysisView.h" #include MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) @@ -83,8 +84,8 @@ MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) new_view->setDeleteOnClose(false); } break; case AnalysisType::NuclideAnalysisView: { - // new_view = new MeasureAnalysisDataTableView; - // new_view->setDeleteOnClose(false); + new_view = new NuclideAnalysisView; + new_view->setDeleteOnClose(false); } break; case AnalysisType::ParticleInTimeView: { new_view = new ParticleInjectTimeAnalysisView; @@ -106,6 +107,7 @@ MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) new_view = new AntiConformEnergySpectrumView; new_view->setDeleteOnClose(false); } break; + default: break; } diff --git a/src/NuclideAnalysisView/NuclideAnalysisView.cpp b/src/NuclideAnalysisView/NuclideAnalysisView.cpp new file mode 100644 index 0000000..4115188 --- /dev/null +++ b/src/NuclideAnalysisView/NuclideAnalysisView.cpp @@ -0,0 +1,138 @@ +#include "NuclideAnalysisView.h" +#include "CustomQwtPlot.h" +#include "csv.h" +#include +#include +#include +#include +#include "MeasureAnalysisProjectModel.h" +#include +#include +#include +#include +NuclideAnalysisView::NuclideAnalysisView(QWidget* parent) + : MeasureAnalysisView { parent } +{ + this->setViewType(PlotFrame); + QHBoxLayout* layout = new QHBoxLayout(this); + this->_plot = new CustomQwtPlot(this); + layout->addWidget(this->_plot); + setupPlot(); + this->_menu = new QMenu(this); + setupMenu(); +} + +NuclideAnalysisView::~NuclideAnalysisView() +{ + LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName())); +} + +void NuclideAnalysisView::InitViewWorkspace(const QString& project_name) +{ + Q_UNUSED(project_name); + if (project_name.isEmpty()) + return; + auto project_model = ProjectList::Instance()->GetProjectModel(project_name); + if (!project_model) + return; + QDir project_dir(project_model->GetProjectDir()); + _workspace = project_dir.filePath(this->GetViewName()); + if (!QDir(_workspace).exists()) + project_dir.mkpath(_workspace); +} + +void NuclideAnalysisView::SetAnalyzeDataFilename(const QMap& data_files_set) +{ + if (!data_files_set.isEmpty()) { + const QString& data_name = data_files_set.firstKey(); + const QString& data_filename = data_files_set.first().toString(); + if (QFileInfo(data_filename).exists()) { + loadDataFromFile(data_name, data_filename); + } + } +} + +void NuclideAnalysisView::setupPlot() +{ + _plot->setCanvasBackground(Qt::white); + QwtPlotCanvas* canvas = qobject_cast(_plot->canvas()); + canvas->setFrameStyle(QFrame::NoFrame); + QFont font = this->font(); + font.setBold(false); + QwtText energy_label = QStringLiteral(u"能量(KeV)"); + energy_label.setFont(font); + QwtText count_label = QStringLiteral(u"计数"); + count_label.setFont(font); + _plot->setAxisTitle(QwtPlot::xBottom, energy_label); + _plot->setAxisTitle(QwtPlot::yLeft, count_label); + // 设置轴自动缩放 + _plot->setAxisAutoScale(QwtPlot::xBottom, true); + _plot->setAxisAutoScale(QwtPlot::yLeft, true); + _plot->enableAxis(QwtPlot::xBottom); + _plot->enableAxis(QwtPlot::yLeft); + _plot->SetAxisDragScale(QwtPlot::xBottom, true); + // 启用鼠标追踪 + _plot->canvas()->setMouseTracking(true); +} + +void NuclideAnalysisView::setupMenu() +{ + this->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &NuclideAnalysisView::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, &NuclideAnalysisView::onActionPlotConfigure); + this->_menu->addSeparator(); + +} + +void NuclideAnalysisView::loadDataFromFile(const QString& data_name, const QString& filename) +{ + // 加载新数据前清空旧数据 + _plot->replot(); + + std::string address_str = QString(QStringLiteral(u"能量(KeV)")).toStdString(); + std::string count_str = QString(QStringLiteral(u"计数")).toStdString(); + io::CSVReader< + 2, + io::trim_chars<' ', '\t'>, + io::double_quote_escape<',', '"'>, + io::throw_on_overflow, + io::empty_line_comment> + reader(QStrToSysPath(filename)); + reader.read_header(io::ignore_extra_column, address_str, count_str); + + double energy; + unsigned long long energy_count; + QVector x, y; + while (reader.read_row(energy, energy_count)) { + x.push_back(energy); + y.push_back(energy_count); + if(_x_max < energy) + _x_max = energy; + if(_y_max < energy_count) + _y_max = energy_count; + } + + _plot->SetAxisInitRange(QwtPlot::xBottom,0.0f,_x_max); + _plot->SetAxisInitRange(QwtPlot::yLeft,0.0f,_y_max); + + // 绘制原始数据曲线 + QwtPlotCurve* curve = new QwtPlotCurve(QStringLiteral(u"原始数据")); + curve->setPen(QPen(Qt::gray, 2)); // 原始数据统一灰色 + curve->setSamples(x, y); + _plot->AddCurve(curve,false); +} + +void NuclideAnalysisView::onActionPlotConfigure() +{ + +} \ No newline at end of file diff --git a/src/NuclideAnalysisView/NuclideAnalysisView.h b/src/NuclideAnalysisView/NuclideAnalysisView.h new file mode 100644 index 0000000..260b2b9 --- /dev/null +++ b/src/NuclideAnalysisView/NuclideAnalysisView.h @@ -0,0 +1,33 @@ +#ifndef NUCLIDEANALYSISVIEW_H +#define NUCLIDEANALYSISVIEW_H +#include +#include +#include +#include +#include +class CustomQwtPlot; +class NuclideAnalysisView : public MeasureAnalysisView +{ + Q_OBJECT +public: + NuclideAnalysisView(QWidget *parent = nullptr); + virtual ~NuclideAnalysisView(); + virtual void InitViewWorkspace(const QString& project_name) override final; + virtual void SetAnalyzeDataFilename(const QMap& data_files_set); + +private: + void setupPlot(); + void setupMenu(); + void loadDataFromFile(const QString &data_name, const QString& filename); +private slots: + void onActionPlotConfigure(); + +private: + CustomQwtPlot* _plot = nullptr; + QString _workspace; + QMenu* _menu = nullptr; + + int _x_max = 0; + int _y_max = 0; +}; +#endif // NUCLIDEANALYSISVIEW_H \ No newline at end of file diff --git a/src/src.pro b/src/src.pro index 1509c70..fcab269 100644 --- a/src/src.pro +++ b/src/src.pro @@ -38,7 +38,10 @@ INCLUDEPATH += \ $${PWD}/2DSpectralCompliance \ $${PWD}/ConformToTheEnergySpectrum \ $${PWD}/NuclideLib \ - $${PWD}/AntiConformEnergySpectrumView + $${PWD}/AntiConformEnergySpectrumView\ + $${PWD}/CoincidenceEventTimeView\ + $${PWD}/NuclideAnalysisView + DEPENDPATH += \ $${PWD}/BusyIndicator \ @@ -57,12 +60,17 @@ DEPENDPATH += \ $${PWD}/2DSpectralCompliance \ $${PWD}/ConformToTheEnergySpectrum \ $${PWD}/NuclideLib \ - $${PWD}/AntiConformEnergySpectrumView + $${PWD}/AntiConformEnergySpectrumView\ + $${PWD}/CoincidenceEventTimeView\ + $${PWD}/NuclideAnalysisView + + SOURCES += \ 2DSpectralCompliance/TwoDSpectralCompliance.cpp \ AboutDlg.cpp \ BusyIndicator/BusyIndicator.cpp \ + CoincidenceEventTimeView/CoincidenceEventTimeView.cpp \ CountRateAnalysisView/CountRateAnalysisView.cpp \ CustomQwtPlot.cpp \ DataProcessWorkPool.cpp \ @@ -79,6 +87,7 @@ SOURCES += \ MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.cpp \ MeasureDeviceParamsConfigView/DeviceParamsTableForm.cpp \ MeasureDeviceParamsConfigView/MeasureDeviceParamsConfigView.cpp \ + NuclideAnalysisView/NuclideAnalysisView.cpp \ NuclideLib/NuclideEditDialog.cpp \ NuclideLib/NuclideRayDialog.cpp \ NuclideLib/NuclideRayListDialog.cpp \ @@ -111,6 +120,7 @@ HEADERS += \ AboutDlg.h \ AnalysisTypeDefine.h \ BusyIndicator/BusyIndicator.h \ + CoincidenceEventTimeView/CoincidenceEventTimeView.h \ CountRateAnalysisView/CountRateAnalysisView.h \ CustomQwtPlot.h \ DataProcessWorkPool.h \ @@ -128,6 +138,7 @@ HEADERS += \ MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.h \ MeasureDeviceParamsConfigView/DeviceParamsTableForm.h \ MeasureDeviceParamsConfigView/MeasureDeviceParamsConfigView.h \ + NuclideAnalysisView/NuclideAnalysisView.h \ NuclideLib/NuclideEditDialog.h \ NuclideLib/NuclideRayDialog.h \ NuclideLib/NuclideRayListDialog.h \