EnergySpectrumAnalyer/src/EnergyCountPlotView/EnergyCountPlotView.cpp

314 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 "EnergyCountPlotView.h"
#include "CustomQwtPlot.h"
#include "csv.h"
#include <GlobalDefine.h>
#include <QHBoxLayout>
#include <QMenu>
#include <QwtLegend>
#include <QwtPlotCanvas>
#include <QwtPlotCurve>
#include <QwtPlotMarker>
#include <QwtScaleMap>
#include <QwtText>
#include <QDialog>
#include <QPushButton>
#include <QCheckBox>
#include <QwtScaleDiv>
#include <QPen>
//能量计数谱
EnergyCountPlotView::EnergyCountPlotView(QWidget *parent)
: MeasureAnalysisView { parent }
{
this->setViewType(PlotFrame);
QHBoxLayout* layout = new QHBoxLayout(this);
this->_plot = new CustomQwtPlot(this);
_roi = new RegionOfInterest();
connect(_roi, &RegionOfInterest::roiSelected,this, &EnergyCountPlotView::slot_roi_data);
layout->addWidget(this->_plot);
setupPlot();
this->_menu = new QMenu(this);
setupMenu();
}
EnergyCountPlotView::~EnergyCountPlotView()
{
LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName()));
}
void EnergyCountPlotView::InitViewWorkspace(const QString &project_name)
{
Q_UNUSED(project_name);
}
void EnergyCountPlotView::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
{
QStringList ch_count_data_name = data_files_set.keys();
std::sort(ch_count_data_name.begin(), ch_count_data_name.end(), [](const QString& a, const QString& b) {
int num_a = ExtractNumberFromString(a);
int num_b = ExtractNumberFromString(b);
return num_a < num_b;
});
for (const QString& ch_count_data_name : ch_count_data_name) {
if (ch_count_data_name.contains(ch_count_data_name)) {
const QString ch_count_data_filename = data_files_set[ch_count_data_name].toString();
QFileInfo fileInfo(ch_count_data_filename);
if (!fileInfo.exists() || fileInfo.size() == 0) {
continue; // 文件不存在或为空,跳过
}
loadDataFromFile(ch_count_data_name, ch_count_data_filename);
}
}
}
void EnergyCountPlotView::setupPlot()
{
_plot->setCanvasBackground(Qt::white);
QwtPlotCanvas* canvas = qobject_cast<QwtPlotCanvas*>(_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);
// 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);
_plot->SetAxisDragScale(QwtPlot::yLeft, true);
_data_selector = new CustomQwtPlotXaxisSelector(_plot->canvas());
_data_selector->setEnabled(false);
}
void EnergyCountPlotView::setupMenu()
{
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &EnergyCountPlotView::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_set_curve_show = this->_menu->addAction(QStringLiteral(u"选择曲线"));
action_set_curve_show->setObjectName("curve_show_setting");
connect(action_set_curve_show, &QAction::triggered, this, &EnergyCountPlotView::onActionCurveShowSetting);
QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置"));
action_plot_config->setObjectName("plot_config");
connect(action_plot_config, &QAction::triggered, this, &EnergyCountPlotView::onActionPlotConfigure);
QAction* action_roi = this->_menu->addAction(QStringLiteral(u"感兴趣区"));
action_roi->setObjectName("roi");
connect(action_roi,&QAction::triggered,this,&EnergyCountPlotView::onActionRoiTriggered);
}
void EnergyCountPlotView::loadDataFromFile(const QString &data_name, const QString &filename)
{
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<double> 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(data_name);
curve->setSamples(x, y);
_plot->AddCurve(curve);
}
QwtPlotMarker *EnergyCountPlotView::createVLine(double x, Qt::GlobalColor color, double lineWidth)
{
QwtPlotMarker* marker = new QwtPlotMarker();
marker->setXValue(x);
marker->setLineStyle(QwtPlotMarker::VLine);
QPen pen(color);
pen.setWidthF(lineWidth);
marker->setLinePen(pen);
marker->attach(_plot);
return marker;
}
void EnergyCountPlotView::clearAllRoiMarkers()
{
for (auto marker : _roiMarkers)
{
marker->detach(); // 从绘图面板解绑
delete marker; // 销毁对象
}
_roiMarkers.clear();
_plot->replot(); // 刷新画布清除线条
}
void EnergyCountPlotView::updateView(const QMap<QString, QVariant>& data_files_set)
{
// 清除现有所有曲线
for (QwtPlotCurve* curve : this->_plot->GetCurveList()) {
curve->detach();
delete curve;
}
_plot->clearCurve();
// 重新加载数据
if (!data_files_set.isEmpty()) {
SetAnalyzeDataFilename(data_files_set);
}
// 清除标记并重绘
this->_plot->CleanMarkers();
this->_plot->CleanZoneItems();
this->_plot->ResetPlot();
this->_plot->replot();
}
void EnergyCountPlotView::onActionCurveShowSetting()
{
if (!_curve_show_setting_dlg) {
_curve_show_setting_dlg = new QDialog(this, Qt::Dialog | Qt::WindowCloseButtonHint);
_curve_show_setting_dlg->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
_curve_show_setting_dlg->setSizeGripEnabled(false);
_curve_show_setting_dlg->setWindowTitle(QString(QStringLiteral(u"选择%1曲线显示").arg(this->_plot->title().text())));
_curve_show_setting_dlg->setWindowModality(Qt::WindowModal);
_curve_show_setting_dlg->setModal(false);
QVBoxLayout* layout = new QVBoxLayout(_curve_show_setting_dlg);
const QString& all_ch_text = QStringLiteral(u"全通道");
QStringList list_ch_names;
for (QwtPlotCurve* curve : this->_plot->GetCurveList()) {
const QString& every_ch_text = curve->title().text();
if ( all_ch_text != every_ch_text ) {
list_ch_names.append(every_ch_text);
}
}
std::sort(list_ch_names.begin(), list_ch_names.end(), [](const QString& a, const QString& b) {
int num_a = ExtractNumberFromString(a);
int num_b = ExtractNumberFromString(b);
return num_a < num_b;
});
// 自动计算多列排布
int num_columns = std::sqrt(this->_plot->GetCurveList().size());
if (num_columns == 0)
num_columns = 1;
QVBoxLayout* checkbox_layout = new QVBoxLayout();
QHBoxLayout* checkbox_column_layout = new QHBoxLayout();
QMap<QwtPlotCurve*, QCheckBox*> curve_checkbox_map;
auto addCurveToLayout = [&](const QString& curve_name){
QwtPlotCurve* curve = this->_plot->GetCurve(curve_name);
QCheckBox* check_box = new QCheckBox(curve->title().text());
check_box->setChecked(curve->isVisible());
checkbox_column_layout->addWidget(check_box);
connect(check_box, &QCheckBox::stateChanged, [curve](int state) {
curve->setVisible(state == Qt::Checked);
curve->plot()->replot();
});
curve_checkbox_map[curve] = check_box;
if (checkbox_column_layout->count() >= num_columns) {
checkbox_layout->addLayout(checkbox_column_layout);
checkbox_column_layout = new QHBoxLayout();
}
};
addCurveToLayout(all_ch_text);
for (const QString& ch_name : list_ch_names) {
addCurveToLayout(ch_name);
}
if (checkbox_column_layout->count() < num_columns) {
checkbox_column_layout->addStretch();
}
checkbox_layout->addLayout(checkbox_column_layout);
// 全选和反选
auto curveCheckboxUpdate = [this, curve_checkbox_map]() {
for (QwtPlotCurve* curve : this->_plot->GetCurveList()) {
curve_checkbox_map[curve]->setChecked(curve->isVisible());
}
};
QHBoxLayout* button_layout = new QHBoxLayout();
QPushButton* btn_all_select = new QPushButton(QString(QStringLiteral(u"全选")));
connect(btn_all_select, &QPushButton::clicked, [this, curveCheckboxUpdate]() {
for (QwtPlotCurve* curve : this->_plot->GetCurveList()) {
curve->setVisible(true);
}
curveCheckboxUpdate();
this->_plot->replot();
});
button_layout->addWidget(btn_all_select);
QPushButton* btn_reserve_select = new QPushButton(QString(QStringLiteral(u"反选")));
connect(btn_reserve_select, &QPushButton::clicked, [this, curveCheckboxUpdate]() {
for (QwtPlotCurve* curve : this->_plot->GetCurveList()) {
curve->setVisible(!curve->isVisible());
}
curveCheckboxUpdate();
this->_plot->replot();
});
button_layout->addWidget(btn_reserve_select);
layout->addLayout(button_layout);
layout->addLayout(checkbox_layout);
}
_curve_show_setting_dlg->show();
}
void EnergyCountPlotView::onActionPlotConfigure()
{
}
void EnergyCountPlotView::onActionRoiTriggered()
{
clearAllRoiMarkers();
_roi->show();
}
void EnergyCountPlotView::slot_roi_data(ROIItem &item)
{
clearAllRoiMarkers();
// 第一组起始1、结束1 红色竖线,必须存在才插入,所以一定绘制
_roiMarkers.append(createVLine(item.s1, Qt::red, 1.2));
_roiMarkers.append(createVLine(item.e1, Qt::red, 1.2));
// 第二组起始2、结束2 有有效数值才绘制,无值跳过
bool secondGroupValid = !(qIsNaN(item.s2) || qIsNaN(item.e2) || (item.s2 == 0 && item.e2 == 0));
if (secondGroupValid)
{
_roiMarkers.append(createVLine(item.s2, Qt::blue, 1.2));
_roiMarkers.append(createVLine(item.e2, Qt::blue, 1.2));
}
_plot->replot();
}