新增手动寻峰功能
This commit is contained in:
parent
36f05cb098
commit
08eaff9122
|
|
@ -84,7 +84,6 @@ void CountRateAnalysisView::setData(QVector<ParticleInjectTime> data)
|
||||||
const int nVecSize = nAllS / nInv;
|
const int nVecSize = nAllS / nInv;
|
||||||
QVector<double> vec(nVecSize); // 默认初始化为0
|
QVector<double> vec(nVecSize); // 默认初始化为0
|
||||||
|
|
||||||
|
|
||||||
double x_max = 0;
|
double x_max = 0;
|
||||||
double y_max = 0;
|
double y_max = 0;
|
||||||
for(auto info : data) {
|
for(auto info : data) {
|
||||||
|
|
|
||||||
|
|
@ -159,11 +159,28 @@ bool CustomQwtPlotXaxisSelector::end(bool ok)
|
||||||
plot()->replot();
|
plot()->replot();
|
||||||
}
|
}
|
||||||
if ( (_max_x - _min_x) > 3 ) {
|
if ( (_max_x - _min_x) > 3 ) {
|
||||||
emit selectionFinished(_min_x, _max_x);
|
if(_isShowEnergy)
|
||||||
|
{
|
||||||
|
emit selectionFinished(_min_x, _max_x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit selectionFinishedPeak(_min_x, _max_x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return QwtPlotPicker::end(ok);
|
return QwtPlotPicker::end(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CustomQwtPlotXaxisSelector::isShowEnergy() const
|
||||||
|
{
|
||||||
|
return _isShowEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomQwtPlotXaxisSelector::setIsShowEnergy(bool newIsShowEnergy)
|
||||||
|
{
|
||||||
|
_isShowEnergy = newIsShowEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
CustomQwtPlot::CustomQwtPlot(QWidget *parent)
|
CustomQwtPlot::CustomQwtPlot(QWidget *parent)
|
||||||
: QwtPlot(parent)
|
: QwtPlot(parent)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,12 @@ public:
|
||||||
double selectedMaxX() const;
|
double selectedMaxX() const;
|
||||||
void clearSelection();
|
void clearSelection();
|
||||||
|
|
||||||
|
bool isShowEnergy() const;
|
||||||
|
void setIsShowEnergy(bool newIsShowEnergy);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void selectionFinished(double min_x, double max_x);
|
void selectionFinished(double min_x, double max_x);
|
||||||
|
void selectionFinishedPeak(double min_x, double max_x);
|
||||||
protected:
|
protected:
|
||||||
virtual void move(const QPoint& pos) override;
|
virtual void move(const QPoint& pos) override;
|
||||||
virtual bool end(bool ok) override;
|
virtual bool end(bool ok) override;
|
||||||
|
|
@ -54,6 +57,7 @@ private:
|
||||||
QwtPlotShapeItem* _overlay = nullptr;
|
QwtPlotShapeItem* _overlay = nullptr;
|
||||||
double _min_x;
|
double _min_x;
|
||||||
double _max_x;
|
double _max_x;
|
||||||
|
bool _isShowEnergy;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CustomQwtPlot : public QwtPlot
|
class CustomQwtPlot : public QwtPlot
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "DataCalcProcess/FindPeaksBySvd.h"
|
#include "DataCalcProcess/FindPeaksBySvd.h"
|
||||||
#include "DataCalcProcess/GaussPolyCoe.h"
|
#include "DataCalcProcess/GaussPolyCoe.h"
|
||||||
#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h"
|
#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h"
|
||||||
|
#include "DataCalcProcess/AdaptiveSimpsonIntegrate.h"
|
||||||
#include "EnergyScaleDataModel.h"
|
#include "EnergyScaleDataModel.h"
|
||||||
#include "DataCalcProcess/CoincidenceSpectrumProcess.h"
|
#include "DataCalcProcess/CoincidenceSpectrumProcess.h"
|
||||||
#include "BackgroundTaskListModel.h"
|
#include "BackgroundTaskListModel.h"
|
||||||
|
|
@ -588,17 +589,50 @@ bool AutoFindPeaksTask::IsValidSetWorkParameters() const
|
||||||
bool AutoFindPeaksTask::processTask()
|
bool AutoFindPeaksTask::processTask()
|
||||||
{
|
{
|
||||||
QString result_filename = QDir(this->_result_dir).filePath(QStringLiteral(u"自动寻峰结果.csv"));
|
QString result_filename = QDir(this->_result_dir).filePath(QStringLiteral(u"自动寻峰结果.csv"));
|
||||||
std::ofstream out_file(QStrToSysPath(result_filename));
|
const std::string sys_result_path = QStrToSysPath(result_filename);
|
||||||
std::string channel_str = QString(QStringLiteral(u"通道")).toStdString();
|
bool need_write_header = false;
|
||||||
std::string addr_str = QString(QStringLiteral(u"峰位")).toStdString();
|
{
|
||||||
std::string left_addr_str = QString(QStringLiteral(u"左边界")).toStdString();
|
// 以只读模式打开文件,判断是否为空
|
||||||
std::string lright_addr_str = QString(QStringLiteral(u"右边界")).toStdString();
|
std::ifstream check_file(sys_result_path);
|
||||||
std::string width_str = QString(QStringLiteral(u"峰宽")).toStdString();
|
if (!check_file.is_open())
|
||||||
std::string height_str = QString(QStringLiteral(u"峰高")).toStdString();
|
{
|
||||||
std::string fwhm_str = QString(QStringLiteral(u"FWHM")).toStdString();
|
// 文件不存在,需要写表头
|
||||||
std::string area_str = QString(QStringLiteral(u"峰面积")).toStdString();
|
need_write_header = true;
|
||||||
out_file << channel_str << "," << addr_str << "," << left_addr_str << "," << lright_addr_str
|
}
|
||||||
<< "," << width_str << "," << height_str << "," << fwhm_str << "," << area_str << "\n";
|
else
|
||||||
|
{
|
||||||
|
// 文件存在,判断是否为空文件
|
||||||
|
check_file.seekg(0, std::ios::end);
|
||||||
|
std::streampos file_size = check_file.tellg();
|
||||||
|
if (file_size == 0)
|
||||||
|
{
|
||||||
|
need_write_header = true;
|
||||||
|
}
|
||||||
|
check_file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream out_file(QStrToSysPath(result_filename),std::ios::app);
|
||||||
|
if (!out_file.is_open())
|
||||||
|
{
|
||||||
|
LOG_WARN(QStringLiteral(u"[%1]无法打开寻峰结果文件:%2").arg(this->GetProjectName()).arg(result_filename));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仅空文件才写入表头
|
||||||
|
if (need_write_header)
|
||||||
|
{
|
||||||
|
std::string channel_str = QString(QStringLiteral(u"通道")).toStdString();
|
||||||
|
std::string addr_str = QString(QStringLiteral(u"峰位")).toStdString();
|
||||||
|
std::string left_addr_str = QString(QStringLiteral(u"左边界")).toStdString();
|
||||||
|
std::string lright_addr_str = QString(QStringLiteral(u"右边界")).toStdString();
|
||||||
|
std::string width_str = QString(QStringLiteral(u"峰宽")).toStdString();
|
||||||
|
std::string height_str = QString(QStringLiteral(u"峰高")).toStdString();
|
||||||
|
std::string fwhm_str = QString(QStringLiteral(u"FWHM")).toStdString();
|
||||||
|
std::string area_str = QString(QStringLiteral(u"峰面积")).toStdString();
|
||||||
|
out_file << channel_str << "," << addr_str << "," << left_addr_str << "," << lright_addr_str
|
||||||
|
<< "," << width_str << "," << height_str << "," << fwhm_str << "," << area_str << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
QStringList ch_count_data_name = this->_data_files_set.keys();
|
QStringList ch_count_data_name = this->_data_files_set.keys();
|
||||||
std::sort(ch_count_data_name.begin(), ch_count_data_name.end(), [](const QString& a, const QString& b) {
|
std::sort(ch_count_data_name.begin(), ch_count_data_name.end(), [](const QString& a, const QString& b) {
|
||||||
|
|
@ -1480,3 +1514,166 @@ void RealtimeGvfDataWorker::changeEnergyCountData(QList<ParticleData> &dataList,
|
||||||
LOG_WARN(QStringLiteral(u"部分通道的能量计数数据写入失败"));
|
LOG_WARN(QStringLiteral(u"部分通道的能量计数数据写入失败"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
QString ManualFindPeaksTask::GetTaskName()
|
||||||
|
{
|
||||||
|
return QStringLiteral(u"[%1]粒子通道计数谱手动寻峰处理").arg(this->GetProjectName());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManualFindPeaksTask::SetAnalysisType(AnalysisType analysis_type)
|
||||||
|
{
|
||||||
|
this->_analysis_type = analysis_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManualFindPeaksTask::SetDataMap(const QMap<QString, ChannelSelectionData> &data_set)
|
||||||
|
{
|
||||||
|
_dataManual = data_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManualFindPeaksTask::SetResultDir(const QString &result_dir)
|
||||||
|
{
|
||||||
|
this->_result_dir = result_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManualFindPeaksTask::SetFindPeakSetpWinWidth(int step_win_width)
|
||||||
|
{
|
||||||
|
this->_step_win_width = step_win_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ManualFindPeaksTask::IsValidSetWorkParameters() const
|
||||||
|
{
|
||||||
|
return (!this->_dataManual.isEmpty())
|
||||||
|
&& (!this->_result_dir.isEmpty())
|
||||||
|
&& (this->_step_win_width > 0)
|
||||||
|
&& DataProcessTask::IsValidSetWorkParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ManualFindPeaksTask::processTask()
|
||||||
|
{
|
||||||
|
QString result_filename = QDir(this->_result_dir).filePath(QStringLiteral(u"自动寻峰结果.csv"));
|
||||||
|
const std::string sys_result_path = QStrToSysPath(result_filename);
|
||||||
|
bool need_write_header = false;
|
||||||
|
{
|
||||||
|
// 以只读模式打开文件,判断是否为空
|
||||||
|
std::ifstream check_file(sys_result_path);
|
||||||
|
if (!check_file.is_open())
|
||||||
|
{
|
||||||
|
need_write_header = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
check_file.seekg(0, std::ios::end);
|
||||||
|
std::streampos file_size = check_file.tellg();
|
||||||
|
if (file_size == 0)
|
||||||
|
{
|
||||||
|
need_write_header = true;
|
||||||
|
}
|
||||||
|
check_file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::ofstream out_file(sys_result_path,std::ios::app);
|
||||||
|
|
||||||
|
// 仅空文件才写入表头
|
||||||
|
if (need_write_header)
|
||||||
|
{
|
||||||
|
std::string channel_str = QString(QStringLiteral(u"通道")).toStdString();
|
||||||
|
std::string addr_str = QString(QStringLiteral(u"峰位")).toStdString();
|
||||||
|
std::string left_addr_str = QString(QStringLiteral(u"左边界")).toStdString();
|
||||||
|
std::string lright_addr_str = QString(QStringLiteral(u"右边界")).toStdString();
|
||||||
|
std::string width_str = QString(QStringLiteral(u"峰宽")).toStdString();
|
||||||
|
std::string height_str = QString(QStringLiteral(u"峰高")).toStdString();
|
||||||
|
std::string fwhm_str = QString(QStringLiteral(u"FWHM")).toStdString();
|
||||||
|
std::string area_str = QString(QStringLiteral(u"峰面积")).toStdString();
|
||||||
|
out_file << channel_str << "," << addr_str << "," << left_addr_str << "," << lright_addr_str
|
||||||
|
<< "," << width_str << "," << height_str << "," << fwhm_str << "," << area_str << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按通道号排序
|
||||||
|
QStringList ch_name_list = this->_dataManual.keys();
|
||||||
|
std::sort(ch_name_list.begin(), ch_name_list.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& channel_name : ch_name_list) {
|
||||||
|
const ChannelSelectionData& chData = _dataManual.value(channel_name);
|
||||||
|
|
||||||
|
if (chData.x.size() < 6) {
|
||||||
|
LOG_WARN(QStringLiteral(u"[%1]%2 框选数据点过少(<6),跳过拟合")
|
||||||
|
.arg(this->GetProjectName()).arg(channel_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转 arma 格式
|
||||||
|
arma::vec armaX(chData.x.size()), armaY(chData.x.size());
|
||||||
|
for (size_t i = 0; i < chData.x.size(); ++i) {
|
||||||
|
armaX(i) = chData.x[i];
|
||||||
|
armaY(i) = chData.y[i];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
arma::vec p0 = EstimatePhotonPeakModelInitialParams(armaX, armaY);
|
||||||
|
arma::vec p_fit = NolinearLeastSquaresCurveFit::Lsqcurvefit(
|
||||||
|
PhotonPeakModel, armaX, armaY, p0
|
||||||
|
);
|
||||||
|
double amplitude = p_fit(0); // 峰振幅
|
||||||
|
double sigma = p_fit(1); // 高斯sigma
|
||||||
|
double center = p_fit(5); // 峰中心(峰位)
|
||||||
|
double fwhm = sigma * 2.355;
|
||||||
|
double baseline = p_fit(4); // 本底
|
||||||
|
double peakHeight = amplitude + baseline; // 峰高 = 振幅 + 本底
|
||||||
|
|
||||||
|
int left_bound = static_cast<int>(std::round(center - 3.0 * sigma));
|
||||||
|
int right_bound = static_cast<int>(std::round(center + 3.0 * sigma));
|
||||||
|
int peak_width = right_bound - left_bound;
|
||||||
|
|
||||||
|
int peak_pos = static_cast<int>(std::round(center));
|
||||||
|
|
||||||
|
AdaptiveSimpsonIntegrate::FitFunction fitFunc;
|
||||||
|
fitFunc.A = p_fit(0);
|
||||||
|
fitFunc.delt = p_fit(1);
|
||||||
|
fitFunc.H = p_fit(2);
|
||||||
|
fitFunc.W = p_fit(3);
|
||||||
|
fitFunc.C = p_fit(4);
|
||||||
|
fitFunc.P = p_fit(5);
|
||||||
|
double lower = fitFunc.P - 3.0 * fitFunc.delt;
|
||||||
|
double upper = fitFunc.P + 3.0 * fitFunc.delt;
|
||||||
|
double peak_area = AdaptiveSimpsonIntegrate::integrate(fitFunc, lower, upper);
|
||||||
|
|
||||||
|
// 5. 写入CSV
|
||||||
|
std::string channel_std = channel_name.toStdString();
|
||||||
|
out_file << channel_std << ","
|
||||||
|
<< peak_pos << ","
|
||||||
|
<< left_bound << ","
|
||||||
|
<< right_bound << ","
|
||||||
|
<< peak_width << ","
|
||||||
|
<< static_cast<int>(std::round(peakHeight)) << ","
|
||||||
|
<< static_cast<int>(std::round(fwhm)) << ","
|
||||||
|
<< peak_area << "\n";
|
||||||
|
// LOG_INFO(QStringLiteral(u"[%1]%2 手动寻峰完成:峰位=%3, FWHM=%4, 面积=%5")
|
||||||
|
// .arg(this->GetProjectName()).arg(channel_name)
|
||||||
|
// .arg(peak_pos).arg(fwhm, 0, 'f', 2).arg(peak_area, 0, 'f', 2));
|
||||||
|
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_WARN(QStringLiteral(u"[%1]%2 手动寻峰拟合异常:%3")
|
||||||
|
.arg(this->GetProjectName()).arg(channel_name)
|
||||||
|
.arg(QString::fromStdString(e.what())));
|
||||||
|
continue;
|
||||||
|
} catch (...) {
|
||||||
|
LOG_WARN(QStringLiteral(u"[%1]%2 手动寻峰拟合未知异常")
|
||||||
|
.arg(this->GetProjectName()).arg(channel_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_file.close();
|
||||||
|
const QString& project_name = GetProjectName();
|
||||||
|
MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name);
|
||||||
|
if (project_model != nullptr) {
|
||||||
|
project_model->SetAnalysisCustomData(
|
||||||
|
this->_analysis_type,
|
||||||
|
QString("AutoFindPeaksResult"),
|
||||||
|
result_filename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LOG_INFO(QStringLiteral(u"[%1]手动框选区域寻峰全部完成.").arg(this->GetProjectName()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,13 @@
|
||||||
class EnergyScaleDataModel;
|
class EnergyScaleDataModel;
|
||||||
class MeasureAnalysisProjectModel;
|
class MeasureAnalysisProjectModel;
|
||||||
|
|
||||||
|
struct ChannelSelectionData {
|
||||||
|
QString channelName; // 通道名,如"通道1"
|
||||||
|
QVector<int> x; // 框选范围内的道址
|
||||||
|
QVector<int> y; // 对应计数
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace DataProcessWorkPool
|
namespace DataProcessWorkPool
|
||||||
{
|
{
|
||||||
class DataProcessTask : public QRunnable
|
class DataProcessTask : public QRunnable
|
||||||
|
|
@ -103,7 +110,7 @@ namespace DataProcessWorkPool
|
||||||
private:
|
private:
|
||||||
virtual bool processTask() override;
|
virtual bool processTask() override;
|
||||||
};
|
};
|
||||||
|
//自动寻峰
|
||||||
class AutoFindPeaksTask : public DataProcessTask
|
class AutoFindPeaksTask : public DataProcessTask
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -121,6 +128,27 @@ namespace DataProcessWorkPool
|
||||||
QString _result_dir;
|
QString _result_dir;
|
||||||
int _step_win_width = 7;
|
int _step_win_width = 7;
|
||||||
};
|
};
|
||||||
|
//手动寻峰
|
||||||
|
class ManualFindPeaksTask : public DataProcessTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString GetTaskName();
|
||||||
|
void SetAnalysisType(AnalysisType analysis_type);
|
||||||
|
// void SetDataFileList(const QMap<QString, QVariant>& data_files_set);
|
||||||
|
void SetDataMap(const QMap<QString,ChannelSelectionData>& data_set);
|
||||||
|
void SetResultDir(const QString& result_dir);
|
||||||
|
void SetFindPeakSetpWinWidth(int step_win_width);
|
||||||
|
virtual bool IsValidSetWorkParameters() const override;
|
||||||
|
private:
|
||||||
|
virtual bool processTask() override;
|
||||||
|
private:
|
||||||
|
AnalysisType _analysis_type;
|
||||||
|
// QMap<QString, QVariant> _data_files_set;
|
||||||
|
QString _result_dir;
|
||||||
|
QMap<QString,ChannelSelectionData> _dataManual;
|
||||||
|
int _step_win_width = 7;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class ChannelEnergyScaleFittingTask : public DataProcessTask
|
class ChannelEnergyScaleFittingTask : public DataProcessTask
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ BatchEnergyScaleDialog::BatchEnergyScaleDialog(QWidget* parent)
|
||||||
|
|
||||||
ui->tablew_process_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
ui->tablew_process_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
ui->tablew_process_data->horizontalHeader()->setSectionResizeMode(
|
ui->tablew_process_data->horizontalHeader()->setSectionResizeMode(
|
||||||
ui->tablew_process_data->columnCount() - 1, QHeaderView::ResizeToContents);
|
ui->tablew_process_data->columnCount() - 1, QHeaderView::ResizeToContents);
|
||||||
ui->tablew_process_data->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
ui->tablew_process_data->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
|
|
||||||
ui->filter_set_energy_combo_box->addItem(QStringLiteral(u"所有设置能量"));
|
ui->filter_set_energy_combo_box->addItem(QStringLiteral(u"所有设置能量"));
|
||||||
|
|
|
||||||
|
|
@ -290,3 +290,8 @@ QVariantMap FindPeaksResultDialog::peakInfo(QTableWidgetItem *item, bool show_pe
|
||||||
peak_infos["show_peak_area"] = show_peak_area && show_peak;
|
peak_infos["show_peak_area"] = show_peak_area && show_peak;
|
||||||
return peak_infos;
|
return peak_infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTableWidget *FindPeaksResultDialog::peaks_result_table() const
|
||||||
|
{
|
||||||
|
return _peaks_result_table;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ public:
|
||||||
void SetChannelNameList(const QStringList& ch_name_list);
|
void SetChannelNameList(const QStringList& ch_name_list);
|
||||||
void UpdatePeakResult();
|
void UpdatePeakResult();
|
||||||
QAbstractTableModel *GetPeakResultDataModel() const;
|
QAbstractTableModel *GetPeakResultDataModel() const;
|
||||||
|
|
||||||
private:
|
|
||||||
void saveCurrentPeakResult();
|
void saveCurrentPeakResult();
|
||||||
QVariantMap peakInfo(QTableWidgetItem* item, bool show_peak, bool show_peak_area);
|
QVariantMap peakInfo(QTableWidgetItem* item, bool show_peak, bool show_peak_area);
|
||||||
|
|
||||||
|
QTableWidget *peaks_result_table() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void peakInfoChanged(QVariantMap peak_infos);
|
void peakInfoChanged(QVariantMap peak_infos);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include "ParticleCountPlotView.h"
|
#include "ParticleCountPlotView.h"
|
||||||
#include "CustomQwtPlot.h"
|
#include "CustomQwtPlot.h"
|
||||||
#include "DataProcessWorkPool.h"
|
|
||||||
#include "MeasureAnalysisProjectModel.h"
|
#include "MeasureAnalysisProjectModel.h"
|
||||||
#include "csv.h"
|
#include "csv.h"
|
||||||
#include <GlobalDefine.h>
|
#include <GlobalDefine.h>
|
||||||
|
|
@ -161,7 +160,7 @@ void ParticleCountPlotView::setupMenu()
|
||||||
connect(action_auto_find_peaks, &QAction::triggered, this, &ParticleCountPlotView::onActionAutoFindPeaks);
|
connect(action_auto_find_peaks, &QAction::triggered, this, &ParticleCountPlotView::onActionAutoFindPeaks);
|
||||||
QAction* action_manual_find_peaks = menu_find_peaks->addAction(QStringLiteral(u"手动寻峰"));
|
QAction* action_manual_find_peaks = menu_find_peaks->addAction(QStringLiteral(u"手动寻峰"));
|
||||||
action_manual_find_peaks->setObjectName("manual_find_peaks");
|
action_manual_find_peaks->setObjectName("manual_find_peaks");
|
||||||
connect(action_auto_find_peaks, &QAction::triggered, this, &ParticleCountPlotView::onActionManualFindPeaks);
|
connect(action_manual_find_peaks, &QAction::triggered, this, &ParticleCountPlotView::onActionManualFindPeaks);
|
||||||
QAction* action_set_energy_scale = this->_menu->addAction(QStringLiteral(u"能量刻度"));
|
QAction* action_set_energy_scale = this->_menu->addAction(QStringLiteral(u"能量刻度"));
|
||||||
action_set_energy_scale->setObjectName("energy_scale");
|
action_set_energy_scale->setObjectName("energy_scale");
|
||||||
connect(action_set_energy_scale, &QAction::triggered, this, &ParticleCountPlotView::onActionEnergyScale);
|
connect(action_set_energy_scale, &QAction::triggered, this, &ParticleCountPlotView::onActionEnergyScale);
|
||||||
|
|
@ -205,6 +204,7 @@ void ParticleCountPlotView::setupPlot()
|
||||||
|
|
||||||
_data_selector = new CustomQwtPlotXaxisSelector(_plot->canvas());
|
_data_selector = new CustomQwtPlotXaxisSelector(_plot->canvas());
|
||||||
_data_selector->setEnabled(false);
|
_data_selector->setEnabled(false);
|
||||||
|
connect(_data_selector,&CustomQwtPlotXaxisSelector::selectionFinishedPeak,this,&ParticleCountPlotView::onManualPeakRangeSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleCountPlotView::setupPeakResultDlg()
|
void ParticleCountPlotView::setupPeakResultDlg()
|
||||||
|
|
@ -316,6 +316,8 @@ void ParticleCountPlotView::updatePlotPeakInfo(const QVariantMap &peak_infos)
|
||||||
this->_plot->replot();
|
this->_plot->replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ParticleCountPlotView::onAutoFindPeaksFinished(bool ok, const QString &project_name, const QVariant& data)
|
void ParticleCountPlotView::onAutoFindPeaksFinished(bool ok, const QString &project_name, const QVariant& data)
|
||||||
{
|
{
|
||||||
Q_UNUSED(project_name);
|
Q_UNUSED(project_name);
|
||||||
|
|
@ -460,7 +462,65 @@ void ParticleCountPlotView::onActionAutoFindPeaks()
|
||||||
|
|
||||||
void ParticleCountPlotView::onActionManualFindPeaks()
|
void ParticleCountPlotView::onActionManualFindPeaks()
|
||||||
{
|
{
|
||||||
// _data_selector->setEnabled(true);
|
if (!_data_selector){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_data_selector->setEnabled(true);
|
||||||
|
_data_selector->setIsShowEnergy(false);
|
||||||
|
|
||||||
|
// 自动打开寻峰结果表格方便查看新增峰
|
||||||
|
if (_find_peaks_result_dlg)
|
||||||
|
_find_peaks_result_dlg->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParticleCountPlotView::onManualPeakRangeSelected(double minX, double maxX)
|
||||||
|
{
|
||||||
|
// 关闭框选工具
|
||||||
|
_data_selector->setEnabled(false);
|
||||||
|
// 获取32个通道的框选数据
|
||||||
|
QMap<QString, ChannelSelectionData> allData = getSelectedRangeData(minX, maxX);
|
||||||
|
|
||||||
|
auto manual_find_peaks_task = new DataProcessWorkPool::ManualFindPeaksTask;
|
||||||
|
const QString& project_name = GetProjectName();
|
||||||
|
manual_find_peaks_task->SetAnalysisType(this->GetAnalyzeType());
|
||||||
|
// manual_find_peaks_task->SetDataFileList(this->_data_files_set_ptr);
|
||||||
|
manual_find_peaks_task->SetFindPeakSetpWinWidth(35);
|
||||||
|
manual_find_peaks_task->SetResultDir(this->_workspace);
|
||||||
|
manual_find_peaks_task->SetDataMap(allData);
|
||||||
|
manual_find_peaks_task->SetFinishedNotifier(this, "onAutoFindPeaksFinished", project_name);
|
||||||
|
manual_find_peaks_task->StartTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, ChannelSelectionData> ParticleCountPlotView::getSelectedRangeData(double minX, double maxX)
|
||||||
|
{
|
||||||
|
QMap<QString, ChannelSelectionData> result;
|
||||||
|
|
||||||
|
// 获取所有曲线
|
||||||
|
QList<QwtPlotCurve*> curveList = _plot->GetCurveList();
|
||||||
|
|
||||||
|
for (QwtPlotCurve* curve : curveList) {
|
||||||
|
const QString& chName = curve->title().text();
|
||||||
|
|
||||||
|
ChannelSelectionData chData;
|
||||||
|
chData.channelName = chName;
|
||||||
|
|
||||||
|
// 取曲线原始样本
|
||||||
|
const QwtSeriesData<QPointF>& series = *curve->data();
|
||||||
|
size_t total = series.size();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < total; ++i) {
|
||||||
|
double xVal = series.sample(i).x();
|
||||||
|
double yVal = series.sample(i).y();
|
||||||
|
|
||||||
|
// 筛选在框选范围内的点(含边界)
|
||||||
|
if (xVal >= minX && xVal <= maxX) {
|
||||||
|
chData.x.push_back(xVal);
|
||||||
|
chData.y.push_back(yVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.insert(chName, chData);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleCountPlotView::onActionEnergyScale()
|
void ParticleCountPlotView::onActionEnergyScale()
|
||||||
|
|
@ -468,6 +528,8 @@ void ParticleCountPlotView::onActionEnergyScale()
|
||||||
if (_batch_energy_scale_dlg && _data_selector) {
|
if (_batch_energy_scale_dlg && _data_selector) {
|
||||||
_batch_energy_scale_dlg->show();
|
_batch_energy_scale_dlg->show();
|
||||||
_data_selector->setEnabled(true);
|
_data_selector->setEnabled(true);
|
||||||
|
_data_selector->setIsShowEnergy(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include "MeasureAnalysisView.h"
|
#include "MeasureAnalysisView.h"
|
||||||
|
#include "DataProcessWorkPool.h"
|
||||||
|
|
||||||
class QDialog;
|
class QDialog;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
|
@ -15,6 +16,7 @@ class CustomQwtPlotXaxisSelector;
|
||||||
class BatchEnergyScaleDialog;
|
class BatchEnergyScaleDialog;
|
||||||
class FindPeaksResultDialog;
|
class FindPeaksResultDialog;
|
||||||
|
|
||||||
|
|
||||||
class ParticleCountPlotView : public MeasureAnalysisView
|
class ParticleCountPlotView : public MeasureAnalysisView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -35,6 +37,8 @@ private:
|
||||||
void loadDataFromFile(const QString &data_name, const QString& filename);
|
void loadDataFromFile(const QString &data_name, const QString& filename);
|
||||||
void loadPeaksResultToTable(QTableWidget* peaks_result_table);
|
void loadPeaksResultToTable(QTableWidget* peaks_result_table);
|
||||||
void updatePlotPeakInfo(const QVariantMap& peak_infos);
|
void updatePlotPeakInfo(const QVariantMap& peak_infos);
|
||||||
|
void onManualPeakRangeSelected(double minX, double maxX);
|
||||||
|
QMap<QString, ChannelSelectionData> getSelectedRangeData(double minX, double maxX);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onAutoFindPeaksFinished(bool ok, const QString &project_name, const QVariant& data);
|
void onAutoFindPeaksFinished(bool ok, const QString &project_name, const QVariant& data);
|
||||||
|
|
@ -45,7 +49,6 @@ private slots:
|
||||||
void onActionManualFindPeaks();
|
void onActionManualFindPeaks();
|
||||||
void onActionEnergyScale();
|
void onActionEnergyScale();
|
||||||
void onActionPlotConfigure();
|
void onActionPlotConfigure();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void applyEnergyScale();
|
void applyEnergyScale();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user