diff --git a/src/CustomQwtPlot.cpp b/src/CustomQwtPlot.cpp index 5865f29..8da100b 100644 --- a/src/CustomQwtPlot.cpp +++ b/src/CustomQwtPlot.cpp @@ -58,6 +58,7 @@ void CustomQwtPlot::AddCurve(QwtPlotCurve *curve) { if (curve) { curve->setPen(QPen(getDistinctColorForManyCurves(_curves.count()), 1)); + curve->setZ(0); curve->attach(this); _curves[curve->title().text()] = curve; } @@ -85,9 +86,7 @@ void CustomQwtPlot::AddMarker(QwtPlotMarker *marker, const QString &marker_name, QPen pen = curve->pen(); pen.setWidth(2); marker->setLinePen(pen); - QwtText label_text = marker->label(); - label_text.setColor(Qt::black); - marker->setLabel(label_text); + marker->setZ(20); marker->attach(this); _markers[marker_name][postion] = marker; } @@ -131,6 +130,7 @@ void CustomQwtPlot::AddZoneItem(QwtPlotZoneItem *zone_item, const QString &zone_ if (zone_item) { zone_item->setPen(Qt::transparent); // 无边框 zone_item->setBrush(QColor(0, 120, 215, 95)); // 半透明蓝色(RGBA:A=80 透明度) + zone_item->setZ(10); zone_item->attach(this); _zone_items[zone_item_name] = zone_item; } @@ -276,6 +276,7 @@ CustomQwtPlotXaxisSelector::CustomQwtPlotXaxisSelector(QWidget *canvas) _overlay->setRenderHint(QwtPlotItem::RenderAntialiased); _overlay->setPen(QPen(Qt::red, 2)); _overlay->setBrush(QBrush(QColor(0, 120, 210, 50))); + _overlay->setZ(100); _overlay->attach(plot()); _overlay->setVisible(false); } diff --git a/src/DataCalcProcess/FindPeaksBySvd.cpp b/src/DataCalcProcess/FindPeaksBySvd.cpp index b437225..f7dd1f9 100644 --- a/src/DataCalcProcess/FindPeaksBySvd.cpp +++ b/src/DataCalcProcess/FindPeaksBySvd.cpp @@ -2,7 +2,7 @@ using namespace arma; -std::vector FindPeaksBySvd::FindPeaks(const arma::mat &spec_data, int step_w) +std::vector FindPeaksBySvd::FindPeaks(const arma::mat &spec_data, int step_w) throw(std::string) { std::vector peak_info_vec; try { @@ -131,11 +131,9 @@ std::vector FindPeaksBySvd::FindPeaks(const arma::mat } } catch(const std::exception& e) { - return peak_info_vec; - throw std::string("Find Peaks Exception:") + std::string(e.what()); + throw std::string("Find Peaks Exception, ") + std::string(e.what()); } catch (...) { - return peak_info_vec; throw std::string("Find peaks unkonow exception"); } return peak_info_vec; diff --git a/src/DataCalcProcess/FindPeaksBySvd.h b/src/DataCalcProcess/FindPeaksBySvd.h index 5ec46a7..314486f 100644 --- a/src/DataCalcProcess/FindPeaksBySvd.h +++ b/src/DataCalcProcess/FindPeaksBySvd.h @@ -17,7 +17,7 @@ public: double area = 0.0f; // 峰的面积 } PeakInfo; - std::vector FindPeaks(const arma::mat& spec_data, int step_w = 7); + std::vector FindPeaks(const arma::mat& spec_data, int step_w = 7) throw(std::string); }; diff --git a/src/DataCalcProcess/GaussPolyCoe.cpp b/src/DataCalcProcess/GaussPolyCoe.cpp index bbfeaa9..8cb6007 100644 --- a/src/DataCalcProcess/GaussPolyCoe.cpp +++ b/src/DataCalcProcess/GaussPolyCoe.cpp @@ -4,67 +4,76 @@ using namespace std; vector GaussPolyCoe::GaussianElimination(vector> A, vector b) { - int n = A.size(); - - for (int i = 0; i < n; ++i) { - // 寻找主元 - int maxRow = i; - for (int j = i; j < n; ++j) { - if (abs(A[j][i]) > abs(A[maxRow][i])) { - maxRow = j; - } - } - - // 交换行 - swap(A[i], A[maxRow]); - swap(b[i], b[maxRow]); - - // 归一化主元行 - double pivot = A[i][i]; - if (abs(pivot) < 1e-10) - continue; // 避免除以零 - for (int j = i; j < n; ++j) { - A[i][j] /= pivot; - } - b[i] /= pivot; - - // 消去其他行 - for (int j = 0; j < n; ++j) { - if (j != i && abs(A[j][i]) > 1e-10) { - double factor = A[j][i]; - for (int k = i; k < n; ++k) { - A[j][k] -= factor * A[i][k]; + try { + int n = A.size(); + for (int i = 0; i < n; ++i) { + // 寻找主元 + int maxRow = i; + for (int j = i; j < n; ++j) { + if (abs(A[j][i]) > abs(A[maxRow][i])) { + maxRow = j; + } + } + + // 交换行 + swap(A[i], A[maxRow]); + swap(b[i], b[maxRow]); + + // 归一化主元行 + double pivot = A[i][i]; + if (abs(pivot) < 1e-10) + continue; // 避免除以零 + for (int j = i; j < n; ++j) { + A[i][j] /= pivot; + } + b[i] /= pivot; + + // 消去其他行 + for (int j = 0; j < n; ++j) { + if (j != i && abs(A[j][i]) > 1e-10) { + double factor = A[j][i]; + for (int k = i; k < n; ++k) { + A[j][k] -= factor * A[i][k]; + } + b[j] -= factor * b[i]; } - b[j] -= factor * b[i]; } } + } catch(const std::exception& e) { + throw e; } return b; } vector GaussPolyCoe::PolynomialFit(const vector& x, const vector& y, int degree) { - int n = x.size(); - int m = degree + 1; // 系数个数 + vector coeffs; + try { + int n = x.size(); + int m = degree + 1; // 系数个数 - // 构造正规方程组的矩阵 A^T*A 和向量 A^T*b - vector> AT_A(m, vector(m, 0.0)); - vector AT_b(m, 0.0); + // 构造正规方程组的矩阵 A^T*A 和向量 A^T*b + vector> AT_A(m, vector(m, 0.0)); + vector AT_b(m, 0.0); + + for (int i = 0; i < m; ++i) { + for (int j = 0; j < m; ++j) { + for (int k = 0; k < n; ++k) { + AT_A[i][j] += pow(x[k], i + j); + } + } - for (int i = 0; i < m; ++i) { - for (int j = 0; j < m; ++j) { for (int k = 0; k < n; ++k) { - AT_A[i][j] += pow(x[k], i + j); + AT_b[i] += y[k] * pow(x[k], i); } } - for (int k = 0; k < n; ++k) { - AT_b[i] += y[k] * pow(x[k], i); - } + // 求解线性方程组得到系数 + coeffs = GaussianElimination(AT_A, AT_b); + } catch(const std::exception& e) { + throw e; } - - // 求解线性方程组得到系数 - return GaussianElimination(AT_A, AT_b); + return coeffs; } double GaussPolyCoe::Predict(const vector& coeffs, double x) diff --git a/src/DataProcessWorkPool.cpp b/src/DataProcessWorkPool.cpp index f486742..9ea9fe2 100644 --- a/src/DataProcessWorkPool.cpp +++ b/src/DataProcessWorkPool.cpp @@ -14,7 +14,10 @@ #include #include #include +#include "DataCalcProcess/MathModelDefine.h" #include "DataCalcProcess/FindPeaksBySvd.h" +#include "DataCalcProcess/GaussPolyCoe.h" +#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h" #include using namespace DataProcessWorkPool; @@ -534,7 +537,7 @@ bool ParticleDataSortTask::processEveryChannelParticleData() } catch (const std::exception& e) { const QString& e_what = QString::fromLatin1(e.what()); - QString error = QString(QStringLiteral(u"处理%1异常:%2")).arg(all_channel_particle_data_filename).arg(e_what); + QString error = QString(QStringLiteral(u"处理%1异常:%2")).arg(all_channel_particle_data_filename).arg(QString::fromStdString(e.what())); LOG_ERROR(error) ret_ok = false; } catch (...) { @@ -611,8 +614,14 @@ bool AutoFindPeaksTask::processTask() LOG_WARN(error); continue; } - FindPeaksBySvd peak_svd; - std::vector peak_info_vec = peak_svd.FindPeaks(data, this->_step_win_width); + std::vector peak_info_vec; + try { + peak_info_vec = FindPeaksBySvd().FindPeaks(data, this->_step_win_width); + } catch (const std::string& e) { + QString error = QString(QStringLiteral(u"%1自动寻峰异常:%2!")).arg(ch_count_data_name).arg(QString::fromStdString(e)); + LOG_WARN(error); + continue; + } if (!peak_info_vec.empty()) { for(auto peak_info : peak_info_vec) { int addr = peak_info.pos; @@ -645,3 +654,106 @@ bool AutoFindPeaksTask::processTask() LOG_INFO(info); return true; } + +void ChannelEnergyScaleFittingTask::SetData( + const FitDataMap& channel_enery_scale_fit_data_map, const QMap& fit_degree_map) +{ + this->_channel_enery_scale_fit_data_map = channel_enery_scale_fit_data_map; + this->_fit_degree_map = fit_degree_map; +} + +bool ChannelEnergyScaleFittingTask::IsValidSetWorkParameters() const +{ + return (!this->_channel_enery_scale_fit_data_map.isEmpty()) && (!this->_fit_degree_map.isEmpty()) && DataProcessTask::IsValidSetWorkParameters(); +} + +bool ChannelEnergyScaleFittingTask::processTask() +{ + QVariantMap enery_scale_json_obj_map; + for (const QString& channel : this->_channel_enery_scale_fit_data_map.keys()) { + const QMap >& enery_scale_fit_data = this->_channel_enery_scale_fit_data_map.value(channel); + if (enery_scale_fit_data.isEmpty()) { + continue; + } + int fit_degree = this->_fit_degree_map.value(channel); + if (fit_degree <= 0) { + continue; + } + std::vector vec_x, vec_y1, vec_y2; + for (const int& addr : enery_scale_fit_data.keys()) { + vec_x.push_back(addr); + vec_y1.push_back(enery_scale_fit_data.value(addr)[0]); + vec_y2.push_back(enery_scale_fit_data.value(addr)[1]); + } + std::vector enery_scale_fit_result_coeffs; + try { + enery_scale_fit_result_coeffs = GaussPolyCoe::PolynomialFit(vec_x, vec_y1, fit_degree); + } catch(const std::exception& e) { + QString error = QString(QStringLiteral(u"%1能量刻度多项式%2次拟合异常:%3!")).arg(channel).arg(fit_degree).arg(QString::fromStdString(e.what())); + LOG_WARN(error); + } + arma::vec fwhm_fit_result_coeffs; + try { + fwhm_fit_result_coeffs = NolinearLeastSquaresCurveFit::Lsqcurvefit(FwhmModel, vec_y1, vec_y2, { 1.0, 1.0 }); + } catch(const std::exception& e) { + QString error = QString(QStringLiteral(u"%1分辨率拟合异常:%2!")).arg(channel).arg(QString::fromStdString(e.what())); + LOG_WARN(error); + } + const QString& info = QStringLiteral(u"%1能量刻度拟合完成.").arg(channel); + LOG_INFO(info); + + QVariantList enery_scale_fit_coeffs_val; + for (const double& coeff : enery_scale_fit_result_coeffs) { + enery_scale_fit_coeffs_val.append(coeff); + } + QVariantList fwhm_fit_coeffs_val; + for (const double& coeff : fwhm_fit_result_coeffs) { + fwhm_fit_coeffs_val.append(coeff); + } + QVariantList fit_result_data_item; + for (int i = 0; i < vec_x.size(); i++) { + int addr = vec_x[i]; + double set_energy = vec_y1[i]; + double fit_energy = GaussPolyCoe::Predict(enery_scale_fit_result_coeffs, addr); + double peak_fwhm = vec_y2[i]; + double fit_fwhm = FwhmModel(addr, fwhm_fit_result_coeffs); + QVariantList fit_result_item_data; + fit_result_item_data.append(addr); + fit_result_item_data.append(set_energy); + fit_result_item_data.append(fit_energy); + fit_result_item_data.append(set_energy - fit_energy); + fit_result_item_data.append(peak_fwhm); + fit_result_item_data.append(fit_fwhm); + fit_result_item_data.append(peak_fwhm - fit_fwhm); + fit_result_data_item.append(QVariant::fromValue(fit_result_item_data)); + } + + QVariantMap channel_enery_scale_fit_result_obj_map; + channel_enery_scale_fit_result_obj_map["EneryFitDegree"] = fit_degree; + channel_enery_scale_fit_result_obj_map["EneryFitResultCoeffs"] = QVariant::fromValue(enery_scale_fit_coeffs_val); + channel_enery_scale_fit_result_obj_map["FwhmFitResultCoeffs"] = QVariant::fromValue(fwhm_fit_coeffs_val); + channel_enery_scale_fit_result_obj_map["FitResultData"] = QVariant::fromValue(fit_result_data_item); + enery_scale_json_obj_map.insert(channel, channel_enery_scale_fit_result_obj_map); + } + const QString& project_name = GetProjectName(); + MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name); + if (project_model == nullptr) { + return false; + } + QDir project_dir(project_model->GetProjectDir()); + const QString& enery_scale_data_filename = project_dir.filePath(QStringLiteral(u"能量刻度.csv")); + QJsonDocument enery_scale_fit_result_doc = QJsonDocument::fromVariant(enery_scale_json_obj_map);; + QFile json_file(enery_scale_data_filename); + if (!json_file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QString error = QString(QStringLiteral(u"生成测量分析[%1]能量刻度结果失败!")).arg(project_name); + LOG_WARN(error); + return false; + } + json_file.write(enery_scale_fit_result_doc.toJson()); + json_file.close(); + + project_model->SetEneryScaleFilename(enery_scale_data_filename); + const QString& info = QStringLiteral(u"能量刻度拟合完成."); + LOG_INFO(info); + return true; +} diff --git a/src/DataProcessWorkPool.h b/src/DataProcessWorkPool.h index 7277117..7868a03 100644 --- a/src/DataProcessWorkPool.h +++ b/src/DataProcessWorkPool.h @@ -105,6 +105,19 @@ namespace DataProcessWorkPool QString _result_dir; int _step_win_width = 7; }; + + class ChannelEnergyScaleFittingTask : public DataProcessTask { + public: + typedef QMap > > FitDataMap; + public: + void SetData(const FitDataMap& channel_enery_scale_fit_data_map, const QMap& fit_degree_map); + virtual bool IsValidSetWorkParameters() const override; + private: + virtual bool processTask() override; + private: + FitDataMap _channel_enery_scale_fit_data_map; + QMap _fit_degree_map; + }; } #endif // DATAPROCESSWORKPOOL_H diff --git a/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.cpp b/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.cpp index 75d2a16..c5a1ae1 100644 --- a/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.cpp +++ b/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.cpp @@ -1,6 +1,13 @@ #include "BatchEneryScaleDialog.h" #include "ui_BatchEneryScaleDialog.h" #include +#include "DataProcessWorkPool.h" +#include "GlobalDefine.h" +#include "MeasureAnalysisProjectModel.h" +#include +#include +#include +#include #include BatchEneryScaleDialog::BatchEneryScaleDialog(QWidget* parent) @@ -13,7 +20,7 @@ BatchEneryScaleDialog::BatchEneryScaleDialog(QWidget* parent) this->setWindowModality(Qt::WindowModal); this->setModal(false); - ui->tablew_process_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + ui->tablew_process_data->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->tablew_process_data->horizontalHeader()->setSectionResizeMode( ui->tablew_process_data->columnCount() - 1, QHeaderView::ResizeToContents); ui->tablew_process_data->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); @@ -79,13 +86,11 @@ BatchEneryScaleDialog::BatchEneryScaleDialog(QWidget* parent) if (btn_remove_row) { ui->tablew_process_data->removeRow(row); btn_remove_row->deleteLater(); + this->updateSetEneryFilter(); } } - this->updateSetEneryFilter(); - }); - connect(ui->btn_fit, &QPushButton::clicked, [this](){ - }); + connect(ui->btn_fit, &QPushButton::clicked, this, &BatchEneryScaleDialog::onFitBtnClickedProcess); connect(ui->btn_save, &QPushButton::clicked, [this](){ }); @@ -96,8 +101,14 @@ BatchEneryScaleDialog::~BatchEneryScaleDialog() delete ui; } +void BatchEneryScaleDialog::SetProjectName(const QString &project_name) +{ + this->_project_name = project_name; +} + void BatchEneryScaleDialog::SetChannelNameList(const QStringList &ch_name_list) { + this->_channel_name_list = ch_name_list; ui->filter_channel_combo_box->clear(); ui->filter_channel_combo_box->addItem(QString(QStringLiteral(u"所有通道"))); ui->filter_channel_combo_box->addItems(ch_name_list); @@ -111,6 +122,11 @@ void BatchEneryScaleDialog::SetPeakResultDataModel(QAbstractTableModel* peaks_re } } +void BatchEneryScaleDialog::SetViewWorkspace(const QString &workspace) +{ + this->_workspace = workspace; +} + void BatchEneryScaleDialog::onSelectedScaleRange(double min, double max) { if (!_peaks_result_model) { @@ -152,33 +168,32 @@ void BatchEneryScaleDialog::onSelectedScaleRange(double min, double max) const QString& channel_name = _peaks_result_model->data(_peaks_result_model->index(i, 0)).toString(); int peak_pos = _peaks_result_model->data(_peaks_result_model->index(i, 1)).toInt(); int peak_fwhm = _peaks_result_model->data(_peaks_result_model->index(i, 6)).toInt(); - if (min < peak_pos && peak_pos > max ) { - continue; + if (min < peak_pos && peak_pos < max ) { + int row = ui->tablew_process_data->rowCount(); + ui->tablew_process_data->insertRow(row); + ui->tablew_process_data->setItem(row, 0, new QTableWidgetItem(channel_name)); + ui->tablew_process_data->item(row, 0)->setCheckState(Qt::Unchecked); + ui->tablew_process_data->setItem(row, 1, new QTableWidgetItem(QString::number(peak_pos))); + ui->tablew_process_data->setItem(row, 2, new QTableWidgetItem(QString::number(set_enery))); + ui->tablew_process_data->setItem(row, 3, new QTableWidgetItem); + ui->tablew_process_data->setItem(row, 4, new QTableWidgetItem); + ui->tablew_process_data->setItem(row, 5, new QTableWidgetItem(QString::number(peak_fwhm))); + ui->tablew_process_data->setItem(row, 6, new QTableWidgetItem); + ui->tablew_process_data->setItem(row, 7, new QTableWidgetItem); + QTableWidgetItem* item = new QTableWidgetItem; + ui->tablew_process_data->setItem(row, 8, item); + QPushButton* btn_remove_row = new QPushButton(QStringLiteral(u"删除")); + btn_remove_row->setMaximumWidth(35); + connect(btn_remove_row, &QPushButton::clicked, [this, item, btn_remove_row]() { + item->setCheckState(Qt::Unchecked); + int remove_row = item->row(); + ui->tablew_process_data->removeRow(remove_row); + btn_remove_row->deleteLater(); + this->updateSetEneryFilter(); + }); + ui->tablew_process_data->setCellWidget(row, 8, btn_remove_row); + this->insertSetEneryValueToFilter(set_enery); } - int row = ui->tablew_process_data->rowCount(); - ui->tablew_process_data->insertRow(row); - ui->tablew_process_data->setItem(row, 0, new QTableWidgetItem(channel_name)); - ui->tablew_process_data->item(row, 0)->setCheckState(Qt::Unchecked); - ui->tablew_process_data->setItem(row, 1, new QTableWidgetItem(QString::number(peak_pos))); - ui->tablew_process_data->setItem(row, 2, new QTableWidgetItem(QString::number(set_enery))); - ui->tablew_process_data->setItem(row, 3, new QTableWidgetItem); - ui->tablew_process_data->setItem(row, 4, new QTableWidgetItem); - ui->tablew_process_data->setItem(row, 5, new QTableWidgetItem(QString::number(peak_fwhm))); - ui->tablew_process_data->setItem(row, 6, new QTableWidgetItem); - ui->tablew_process_data->setItem(row, 7, new QTableWidgetItem); - QTableWidgetItem* item = new QTableWidgetItem; - ui->tablew_process_data->setItem(row, 8, item); - QPushButton* btn_remove_row = new QPushButton(QStringLiteral(u"删除")); - btn_remove_row->setMaximumWidth(35); - connect(btn_remove_row, &QPushButton::clicked, [this, item, btn_remove_row]() { - item->setCheckState(Qt::Unchecked); - int remove_row = item->row(); - ui->tablew_process_data->removeRow(remove_row); - btn_remove_row->deleteLater(); - this->updateSetEneryFilter(); - }); - ui->tablew_process_data->setCellWidget(row, 8, btn_remove_row); - this->insertSetEneryValueToFilter(set_enery); } } } @@ -198,7 +213,7 @@ void BatchEneryScaleDialog::insertSetEneryValueToFilter(double enery) void BatchEneryScaleDialog::updateSetEneryFilter() { int item_count = ui->filter_set_enery_combo_box->count(); - for (int index = item_count - 1; index >= 1; --index) { + for (int index = item_count - 1; index > 0; --index) { int count = ui->filter_set_enery_combo_box->itemData(index).toInt(); count = count - 1; ui->filter_set_enery_combo_box->setItemData(index, count); @@ -210,7 +225,106 @@ void BatchEneryScaleDialog::updateSetEneryFilter() ui->filter_set_enery_combo_box->removeItem(index); } } +} +bool BatchEneryScaleDialog::LoadEneryScaleData(const QString &project_name) +{ + MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name); + if (project_model) { + const QString& enery_scale_data_filename = project_model->GetEneryScaleFilename(); + QFile json_file(enery_scale_data_filename); + if (json_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QJsonDocument json_doc = QJsonDocument::fromJson(json_file.readAll()); + json_file.close(); + const QVariantMap& enery_scale_data_map = json_doc.toVariant().toMap(); + if (!enery_scale_data_map.isEmpty()) { + auto row_count = ui->tablew_process_data->rowCount(); + for (int row = row_count - 1; row >= 0; --row) { + QPushButton* btn_remove_row = dynamic_cast(ui->tablew_process_data->cellWidget(row, 8)); + if (btn_remove_row) { + ui->tablew_process_data->removeRow(row); + btn_remove_row->deleteLater(); + this->updateSetEneryFilter(); + } + } + for (const QString& channel_name : this->_channel_name_list) { + if (enery_scale_data_map.contains(channel_name)) { + const QVariantMap& channel_enery_scale_data_map = enery_scale_data_map[channel_name].toMap(); + if (channel_enery_scale_data_map.contains("FitResultData")) { + const QVariantList& fit_result_data_item_list = channel_enery_scale_data_map["FitResultData"].toList(); + for (const QVariant& fit_result_data_item : fit_result_data_item_list) { + const QVariantList& fit_result_data_map = fit_result_data_item.toList(); + int row = ui->tablew_process_data->rowCount(); + ui->tablew_process_data->insertRow(row); + ui->tablew_process_data->setItem(row, 0, new QTableWidgetItem(channel_name)); + ui->tablew_process_data->item(row, 0)->setCheckState(Qt::Unchecked); + ui->tablew_process_data->setItem(row, 1, new QTableWidgetItem(fit_result_data_map[0].toString())); + ui->tablew_process_data->setItem(row, 2, new QTableWidgetItem(fit_result_data_map[1].toString())); + ui->tablew_process_data->setItem(row, 3, new QTableWidgetItem(fit_result_data_map[2].toString())); + ui->tablew_process_data->setItem(row, 4, new QTableWidgetItem(fit_result_data_map[3].toString())); + ui->tablew_process_data->setItem(row, 5, new QTableWidgetItem(fit_result_data_map[4].toString())); + ui->tablew_process_data->setItem(row, 6, new QTableWidgetItem(fit_result_data_map[5].toString())); + ui->tablew_process_data->setItem(row, 7, new QTableWidgetItem(fit_result_data_map[6].toString())); + QTableWidgetItem* item = new QTableWidgetItem; + ui->tablew_process_data->setItem(row, 8, item); + QPushButton* btn_remove_row = new QPushButton(QStringLiteral(u"删除")); + btn_remove_row->setMaximumWidth(35); + connect(btn_remove_row, &QPushButton::clicked, [this, item, btn_remove_row]() { + item->setCheckState(Qt::Unchecked); + int remove_row = item->row(); + ui->tablew_process_data->removeRow(remove_row); + btn_remove_row->deleteLater(); + this->updateSetEneryFilter(); + }); + ui->tablew_process_data->setCellWidget(row, 8, btn_remove_row); + this->insertSetEneryValueToFilter(fit_result_data_map[1].toDouble()); + } + } + } + } + return true; + } + } + } +} + +void BatchEneryScaleDialog::onFitBtnClickedProcess() +{ + QMap fit_degree_map; + DataProcessWorkPool::ChannelEnergyScaleFittingTask::FitDataMap channel_enery_scale_fit_data_map; + for (int i = 0; i < ui->tablew_process_data->rowCount(); i++) { + const QString& channel_name = ui->tablew_process_data->item(i, 0)->text(); + int peak_pos = ui->tablew_process_data->item(i, 1)->text().toInt(); + double enery = ui->tablew_process_data->item(i, 2)->text().toDouble(); + int peak_fwhm = ui->tablew_process_data->item(i, 5)->text().toInt(); + channel_enery_scale_fit_data_map[channel_name].insert(peak_pos, QList() << enery << peak_fwhm); + fit_degree_map[channel_name] = 1; + } + QStringList data_except_channel_name_list; + for (auto it = channel_enery_scale_fit_data_map.begin(); it != channel_enery_scale_fit_data_map.end(); ++it) { + const QString& channel_name = it.key(); + const QMap >& fit_data = it.value(); + if (fit_data.size() < 2) { + data_except_channel_name_list << channel_name; + } + } + if (data_except_channel_name_list.size() > 0) { + const QString& warn_msg = QStringLiteral(u"请为以下通道设置拟合数据:%1").arg(data_except_channel_name_list.join(QStringLiteral(u","))); + LOG_WARN(warn_msg); + QMessageBox::warning(this, QStringLiteral(u"警告"), warn_msg); + return; + } + if (!channel_enery_scale_fit_data_map.empty()) { + auto auto_find_peaks_task = new DataProcessWorkPool::ChannelEnergyScaleFittingTask; + auto_find_peaks_task->SetData(channel_enery_scale_fit_data_map, fit_degree_map); + auto_find_peaks_task->SetFinishedNotifier(this, "onEneryScaleFitFinished", this->_project_name); + auto_find_peaks_task->StartTask(); + } +} + +void BatchEneryScaleDialog::onEneryScaleFitFinished(const QString &project_name) +{ + this->LoadEneryScaleData(project_name); } void BatchEneryScaleDialog::closeEvent(QCloseEvent *e) diff --git a/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.h b/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.h index 1561a30..0f0ea77 100644 --- a/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.h +++ b/src/MeasureAnalysisParticleCountPlotView/BatchEneryScaleDialog.h @@ -17,11 +17,17 @@ public: explicit BatchEneryScaleDialog(QWidget *parent = nullptr); ~BatchEneryScaleDialog(); + void SetProjectName(const QString& project_name); void SetChannelNameList(const QStringList& ch_name_list); void SetPeakResultDataModel(QAbstractTableModel *peaks_result_model); + void SetViewWorkspace(const QString& workspace); + bool LoadEneryScaleData(const QString& project_name); public slots: void onSelectedScaleRange(double min, double max); + void onFitBtnClickedProcess(); +private slots: + void onEneryScaleFitFinished(const QString& project_name); private: void insertSetEneryValueToFilter(double enery); @@ -35,6 +41,9 @@ protected: private: Ui::BatchEneryScaleDialog *ui; + QString _project_name; + QStringList _channel_name_list; + QString _workspace; QAbstractTableModel* _peaks_result_model; }; diff --git a/src/MeasureAnalysisParticleCountPlotView/FindPeaksResultDialog.cpp b/src/MeasureAnalysisParticleCountPlotView/FindPeaksResultDialog.cpp index 780525c..90c12fc 100644 --- a/src/MeasureAnalysisParticleCountPlotView/FindPeaksResultDialog.cpp +++ b/src/MeasureAnalysisParticleCountPlotView/FindPeaksResultDialog.cpp @@ -107,7 +107,8 @@ FindPeaksResultDialog::FindPeaksResultDialog(QWidget *parent) connect(_peaks_result_table, &QTableWidget::itemChanged, [this](QTableWidgetItem* item) { bool is_watch_item_changed = _peaks_result_table->property("WatchItemChanged").toBool(); if (is_watch_item_changed && bool(item->column() == 0)) { - emit peakInfoChanged(peakInfo(item, true, false)); + bool b_show_peak = (item->checkState() == Qt::Checked); + emit peakInfoChanged(peakInfo(item, b_show_peak, false)); } }); connect(_peaks_result_table, &QTableWidget::currentItemChanged, [this](QTableWidgetItem* current, QTableWidgetItem* previous) { @@ -228,7 +229,7 @@ void FindPeaksResultDialog::saveCurrentPeakResult() << fwhm_str << "," << area_str << "\n"; auto row_count = _peaks_result_table->rowCount(); - for (int i = 0; i < row_count - 1; i++) { + for (int i = 0; i < row_count; i++) { std::string channel = _peaks_result_table->item(i, 0)->text().toStdString(); int peak_pos = _peaks_result_table->item(i, 1)->text().toInt(); int left_bound = _peaks_result_table->item(i, 2)->text().toInt(); @@ -269,6 +270,6 @@ QVariantMap FindPeaksResultDialog::peakInfo(QTableWidgetItem *item, bool show_pe peak_infos["peak_fwhm"] = peak_fwhm; peak_infos["peak_area"] = peak_area; peak_infos["checked"] = is_checked || show_peak; - peak_infos["show_peak_area"] = show_peak_area || show_peak; + peak_infos["show_peak_area"] = show_peak_area && show_peak; return peak_infos; } diff --git a/src/MeasureAnalysisParticleCountPlotView/MeasureAnalysisParticleCountPlotView.cpp b/src/MeasureAnalysisParticleCountPlotView/MeasureAnalysisParticleCountPlotView.cpp index 6698831..5ed33ff 100644 --- a/src/MeasureAnalysisParticleCountPlotView/MeasureAnalysisParticleCountPlotView.cpp +++ b/src/MeasureAnalysisParticleCountPlotView/MeasureAnalysisParticleCountPlotView.cpp @@ -48,6 +48,7 @@ MeasureAnalysisParticleCountPlotView::MeasureAnalysisParticleCountPlotView(QWidg MeasureAnalysisParticleCountPlotView::~MeasureAnalysisParticleCountPlotView() { LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName())); + } void MeasureAnalysisParticleCountPlotView::InitViewWorkspace(const QString& project_name) @@ -59,6 +60,7 @@ void MeasureAnalysisParticleCountPlotView::InitViewWorkspace(const QString& proj if (!project_model) { return; } + QDir project_dir(project_model->GetProjectDir()); QString workspace = project_dir.filePath(this->GetViewName()); if (QDir(workspace).exists()) { @@ -66,9 +68,14 @@ void MeasureAnalysisParticleCountPlotView::InitViewWorkspace(const QString& proj } else if (project_dir.mkpath(workspace)) { this->_workspace = workspace; } - const QString& peaks_result_filename = QDir(this->_workspace).filePath(QStringLiteral(u"自动寻峰结果.csv")); + const QString& peaks_result_filename = QDir(workspace).filePath(QStringLiteral(u"自动寻峰结果.csv")); _find_peaks_result_dlg->SetPeakResultDataFilename(peaks_result_filename); _find_peaks_result_dlg->UpdatePeakResult(); + + _batch_enery_scale_dlg->SetProjectName(project_name); + _batch_enery_scale_dlg->SetViewWorkspace(workspace); + _batch_enery_scale_dlg->LoadEneryScaleData(project_name); + } void MeasureAnalysisParticleCountPlotView::SetAnalyzeDataFilename(const QMap& data_files_set) @@ -233,19 +240,33 @@ void MeasureAnalysisParticleCountPlotView::updatePlotPeakInfo(const QVariantMap const QString& postion = QString::number(peak_pos); QwtPlotMarker* peak_marker = this->_plot->GetMarker(channel, postion); - if ((!peak_marker) && is_checked) { - peak_marker = new QwtPlotMarker(); - peak_marker->setLineStyle(QwtPlotMarker::VLine); - peak_marker->setValue(peak_pos, 0.0); - peak_marker->setLabelAlignment(Qt::AlignTop | Qt::AlignRight); - const QString& label_text = QStringLiteral(u"峰位:%1\n峰宽:%2\n左界:%3\n右界:%4\n峰高:%5\nFWHM:%6\n峰面积:%7\n") - .arg(peak_pos).arg(peak_width).arg(left_bound).arg(right_bound) - .arg(peak_height).arg(peak_fwhm).arg(peak_area); + if (is_checked) { + if (!peak_marker) { + peak_marker = new QwtPlotMarker(); + peak_marker->setLineStyle(QwtPlotMarker::VLine); + peak_marker->setValue(peak_pos, 0.0); + peak_marker->setLabelAlignment(Qt::AlignTop | Qt::AlignRight); + const QString& peak_info_text = QStringLiteral(u"峰位:%1\n峰宽:%2\n左界:%3\n右界:%4\n峰高:%5\nFWHM:%6\n峰面积:%7\n") + .arg(peak_pos).arg(peak_width).arg(left_bound).arg(right_bound) + .arg(peak_height).arg(peak_fwhm).arg(peak_area); + peak_marker->setLabel(peak_info_text); + this->_plot->AddMarker(peak_marker, channel, postion); + } + QwtText label_text = peak_marker->label(); + if (is_show_peak_area) { + label_text.setColor(Qt::black); + peak_marker->setZ(peak_marker->z() + 1); + } else { + label_text.setColor(Qt::transparent); + peak_marker->setZ(peak_marker->z() - 1); + } peak_marker->setLabel(label_text); - this->_plot->AddMarker(peak_marker, channel, postion); - } else if (!is_checked) { - this->_plot->RemoveMarker(channel, postion); + } else { + if (peak_marker) { + this->_plot->RemoveMarker(channel, postion); + } } + QwtPlotZoneItem* peak_area_zone_item = this->_plot->GetZoneItem(channel); if (!peak_area_zone_item && is_show_peak_area) { peak_area_zone_item = new QwtPlotZoneItem; diff --git a/src/MeasureAnalysisProjectModel.cpp b/src/MeasureAnalysisProjectModel.cpp index a19210e..aa2975a 100644 --- a/src/MeasureAnalysisProjectModel.cpp +++ b/src/MeasureAnalysisProjectModel.cpp @@ -244,53 +244,43 @@ bool MeasureAnalysisProjectModel::LoadProjectModel(const QString& project_filena this->_project_filename = project_filename; // 从json文件加载项目模型 QFile json_file(this->_project_filename); - if (!json_file.open(QIODevice::ReadOnly | QIODevice::Text)) - { + if (!json_file.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } QJsonDocument json_doc = QJsonDocument::fromJson(json_file.readAll()); json_file.close(); - if (json_doc.isNull()) - { + if (json_doc.isNull()) { return false; } - if (!json_doc.isObject()) - { + if (!json_doc.isObject()) { return false; } QJsonObject json_obj = json_doc.object(); - if (!json_obj.contains("ProjectName")) - { + if (!json_obj.contains("ProjectName")) { return false; } this->_project_name = json_obj["ProjectName"].toString(); - if (!json_obj.contains("SpectrumType")) - { + if (!json_obj.contains("SpectrumType")) { return false; } this->_spec_type = (SpectrumType)json_obj["SpectrumType"].toInt(); - if (!json_obj.contains("IsStandardSource")) - { + if (!json_obj.contains("IsStandardSource")) { return false; } this->_is_std_source = json_obj["IsStandardSource"].toBool(); - if (!json_obj.contains("DescriptionInfo")) - { + if (!json_obj.contains("DescriptionInfo")) { return false; } this->_description_info = json_obj["DescriptionInfo"].toString(); - if (!json_obj.contains("MeasurePresetTime")) - { + if (!json_obj.contains("MeasurePresetTime")) { return false; } this->_measure_preset_time = json_obj["MeasurePresetTime"].toInt(); - if (!json_obj.contains("IsMeasureComplete")) - { + if (!json_obj.contains("IsMeasureComplete")) { return false; } this->_is_measure_complete = json_obj["IsMeasureComplete"].toBool(); - if (!json_obj.contains("ConformTimeWin")) - { + if (!json_obj.contains("ConformTimeWin")) { return false; } this->_conform_time_win = json_obj["ConformTimeWin"].toInt(); @@ -349,7 +339,7 @@ bool MeasureAnalysisProjectModel::LoadProjectModel(const QString& project_filena bool MeasureAnalysisProjectModel::SaveProjectModel() { - auto ProjectRelativeFilename = [this](const QString& abs_filename){ + auto ProjectRelativeFilename = [this](const QString& abs_filename) { QString project_relative_filename; if ( !abs_filename.isEmpty() ) { QFileInfo file_info(abs_filename); @@ -362,9 +352,7 @@ bool MeasureAnalysisProjectModel::SaveProjectModel() } return project_relative_filename; }; - - if (this->_project_filename.isEmpty()) - { + if (this->_project_filename.isEmpty()) { this->_project_filename = QDir(this->_project_dir).filePath(this->_project_name + QString(".msproject"));; } // 将项目模型转换为json对象 @@ -376,28 +364,22 @@ bool MeasureAnalysisProjectModel::SaveProjectModel() project_json_obj_map["MeasurePresetTime"] = int(this->_measure_preset_time); project_json_obj_map["IsMeasureComplete"] = this->_is_measure_complete; project_json_obj_map["ConformTimeWin"] = this->_conform_time_win; - project_json_obj_map["MeasureDeviceParamsCfgFilename"] = ProjectRelativeFilename(this->_measure_device_params_cfg_filename); project_json_obj_map["EneryScaleFilename"] = ProjectRelativeFilename(this->_enery_scale_filename); project_json_obj_map["EfficiencyScaleFilename"] = ProjectRelativeFilename(this->_efficiency_scale_filename); - project_json_obj_map["AllChannelParticleDataFilename"] = ProjectRelativeFilename(this->_all_channel_particle_data_filename); project_json_obj_map["SortedParticleDataFilename"] = ProjectRelativeFilename(this->_sorted_particle_data_filename); - QVariantMap channel_address_count_data_filename_list; for (auto it = this->_channel_address_count_data_filename_list.constBegin(); it != this->_channel_address_count_data_filename_list.constEnd(); ++it) { channel_address_count_data_filename_list[QString::number(it.key())] = ProjectRelativeFilename(it.value()); } project_json_obj_map["ChannelAddressCountDataFilenameList"] = channel_address_count_data_filename_list; - QVariantMap channel_enery_count_data_filename_list; for (auto it = this->_channel_enery_count_data_filename_list.constBegin(); it != this->_channel_enery_count_data_filename_list.constEnd(); ++it) { channel_enery_count_data_filename_list[QString::number(it.key())] = ProjectRelativeFilename(it.value()); } project_json_obj_map["ChannelEneryCountDataFilenameList"] = channel_enery_count_data_filename_list; - project_json_obj_map["AllChannelEneryTotalCountDataFilename"] = ProjectRelativeFilename(this->_all_channel_enery_total_count_data_filename); - QVariantMap time_win_conform_particle_data; for (auto it = this->_time_win_conform_particle_data.constBegin(); it != this->_time_win_conform_particle_data.constEnd(); ++it) { QVariantMap conform_particle_data; @@ -411,8 +393,7 @@ bool MeasureAnalysisProjectModel::SaveProjectModel() // 将项目模型保存到json文件 QJsonDocument json_doc = QJsonDocument::fromVariant(project_json_obj_map); QFile json_file(this->_project_filename); - if (!json_file.open(QIODevice::WriteOnly | QIODevice::Text)) - { + if (!json_file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } json_file.write(json_doc.toJson()); diff --git a/src/MeasureAnalysisTreeView.cpp b/src/MeasureAnalysisTreeView.cpp index 497b673..3213a68 100644 --- a/src/MeasureAnalysisTreeView.cpp +++ b/src/MeasureAnalysisTreeView.cpp @@ -67,11 +67,11 @@ void MeasureAnalysisTreeView::onNodeDoubleClicked(const QModelIndex& index) data_files_set[QStringLiteral(u"粒子数据")] = file_name; MeasureAnalysisView* view = MeasureAnalysisView::NewAnalyzeView(analysis_type); if ( view ) { - view->InitViewWorkspace(project_name); view->SetProjectName(project_name); const auto& view_name = QStringLiteral(u"%1 [%2]").arg(item_text).arg(project_name); view->SetViewName(view_name); view->SetViewDescription(view_name); + view->InitViewWorkspace(project_name); view->SetAnalyzeDataFilename(data_files_set); emit currentItemView(view); } @@ -90,11 +90,11 @@ void MeasureAnalysisTreeView::onNodeDoubleClicked(const QModelIndex& index) data_files_set[QStringLiteral(u"通道%1道址计数").arg(ch_num)] = file_name; MeasureAnalysisView* view = MeasureAnalysisView::NewAnalyzeView(analysis_type); if ( view ) { - view->InitViewWorkspace(project_name); view->SetProjectName(project_name); const auto& view_name = QStringLiteral(u"%1[%2]").arg(item_text).arg(project_name); view->SetViewName(view_name); view->SetViewDescription(view_name); + view->InitViewWorkspace(project_name); view->SetAnalyzeDataFilename(data_files_set); emit currentItemView(view); }