EnergySpectrumAnalyer/src/EnergyCountPeakFitView/EnergyCountPeakFitView.h

173 lines
5.8 KiB
C
Raw Normal View History

#ifndef ENERGYCOUNTPEAKFITVIEW_H
#define ENERGYCOUNTPEAKFITVIEW_H
2026-05-13 11:29:36 +08:00
#include "PeakFitParamsDialog.h"
#include <MeasureAnalysisView.h>
#include <QDateTime>
#include <QJsonArray>
#include <QJsonObject>
2026-05-13 11:29:36 +08:00
#include <QObject>
#include <QRubberBand>
2026-05-13 11:29:36 +08:00
#include <QWidget>
#include <QwtPickerDragRectMachine>
#include <QwtPlotPicker>
#include <qwt_plot_shapeitem.h>
#include "DataCalcProcess/AdaptiveSimpsonIntegrate.h"
2026-05-13 11:29:36 +08:00
#include "DataCalcProcess/FindPeaksBySvd.h"
#include "DataCalcProcess/MathModelDefine.h"
2026-05-13 11:29:36 +08:00
#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h"
2026-05-13 11:29:36 +08:00
struct PeakFitResult {
double center; // 峰中心能量 (keV)
double amplitude; // 高斯振幅
double sigma; // 高斯宽度
double fwhm; // 半高宽 = sigma * 2.355
double area; // 峰面积(积分)
double baseline; // 常数项 C
double sigmoidH; // Sigmoid 项高度 H
double sigmoidW; // Sigmoid 项宽度 W
};
struct FitCurveData {
2026-05-13 11:29:36 +08:00
double amplitude; // 峰幅度
double sigma; // 高斯sigma
double sigmoidH; // Sigmoid高度
double sigmoidW; // Sigmoid宽度
double baseline; // 本底
double center; // 峰中心
double xMin; // 曲线X范围最小值
double xMax; // 曲线X范围最大值
QRectF selectionRect; // 关联的框选区域
double fwhm; // 半高宽
double area; // 峰面积
int selectionIndex; // 框选区域在_selectionRectItems中的索引
int curveStartIndex; // 拟合曲线在_fitCurves中的起始索引每条对应2条曲线
};
struct PeakFitHistoryItem {
QDateTime timestamp;
2026-05-13 11:29:36 +08:00
QList<FitCurveData> curveList; // 存储多条曲线
2026-05-13 11:29:36 +08:00
QJsonObject toJson() const;
static PeakFitHistoryItem fromJson(const QJsonObject& obj);
};
struct CurrentFitRecord {
2026-05-13 11:29:36 +08:00
PeakFitResult result; // 拟合结果
arma::vec params; // 完整拟合参数
double xMin; // X范围最小值
double xMax; // X范围最大值
int historyIndex; // 对应_fitHistoryList中的索引-1表示未保存
CurrentFitRecord()
: historyIndex(-1)
{
} // 构造函数初始化
};
struct DisplayedCurveRef {
int historyIndex; // 对应 _fitHistoryList 的索引
2026-05-13 11:29:36 +08:00
int curveIndex; // 对应 curveList 的索引
int curveStartIndex; // 对应 _fitCurves 中的起始索引一条历史曲线对应2条Qwt曲线拟合+本底)
int rectIndex; // 对应 _selectionRectItems 中的索引
};
2026-05-13 11:29:36 +08:00
class PlotRectItem; // 前向声明
class QMenu;
class CustomQwtPlot;
class CustomQwtPlotXaxisSelector;
2026-04-15 18:17:16 +08:00
class QwtPlotPicker;
class QwtPlotCurve;
class BusyIndicator;
2026-05-13 11:29:36 +08:00
class EnergyCountPeakFitView : public MeasureAnalysisView {
Q_OBJECT
public:
2026-05-13 11:29:36 +08:00
EnergyCountPeakFitView(QWidget* parent = nullptr);
virtual ~EnergyCountPeakFitView();
virtual void InitViewWorkspace(const QString& project_name) override final;
virtual void SetAnalyzeDataFilename(const QMap<QString, QVariant>& data_files_set);
private:
void setupPlot();
void setupMenu();
2026-05-13 11:29:36 +08:00
void loadDataFromFile(const QString& data_name, const QString& filename);
void loadHistoryFromFile();
void saveHistoryToFile();
int saveCurrentFitToHistory(const QRectF& selectionRect);
2026-05-13 11:29:36 +08:00
// 处理鼠标悬停检测
void updateHoverState(const QPoint& mousePos);
2026-05-13 11:29:36 +08:00
// 显示选中的曲线
void displaySelectedCurves(const QList<FitCurveData>& curves, const QList<DisplayedCurveRef>& refs);
//检查指定历史曲线是否当前正在显示
bool isHistoryCurveDisplayed(int historyIndex, int curveIndex) const;
private slots:
void onActionCurveShowSetting();
void onActionPlotConfigure();
2026-04-15 18:17:16 +08:00
void clearAllSelectionRects();
2026-05-13 11:29:36 +08:00
void clearFitCurves(); // 清除所有拟合曲线
void onActionShowFitHistory();
void onActionDeleteHoveredRect();
2026-05-13 11:29:36 +08:00
// 重新拟合当前悬停的框选区域
void onActionRefitCurrentRect();
2026-05-13 11:29:36 +08:00
void onNewFitResultAdded(); // 新拟合结果同步刷新槽
void onHistoryDlgClosed(); // 历史对话框关闭清理槽
2026-04-15 18:17:16 +08:00
protected:
2026-05-13 11:29:36 +08:00
bool eventFilter(QObject* watched, QEvent* event) override; // 事件过滤器
2026-04-15 18:17:16 +08:00
private:
void startSelection(const QPoint& pos);
void updateSelection(const QPoint& pos);
void finishSelection();
void addSelectionRect(const QRectF& plotRect,int index);
void fadeSelectionRectBorders();
2026-04-15 18:17:16 +08:00
2026-05-13 11:29:36 +08:00
QList<PeakFitResult> performPeakFitting(const QVector<double>& x, const QVector<double>& y /*, const arma::vec* userP0 = nullptr*/);
// 根据拟合参数生成曲线
QList<QwtPlotCurve*> createFitCurve(const PeakFitResult& result, arma::vec xVec);
// 更新历史对话框并保持指定的选中状态
void updateHistoryDialogWithSelection(const QList<DisplayedCurveRef>& selectedRefs);
signals:
void newFitResultAdded();
private:
CustomQwtPlot* _plot = nullptr;
QMenu* _menu = nullptr;
QDialog* _curve_show_setting_dlg = nullptr;
CustomQwtPlotXaxisSelector* _data_selector = nullptr;
2026-04-15 18:17:16 +08:00
// 手动框选状态
bool _isSelecting = false;
QPoint _selectionStart;
2026-05-13 11:29:36 +08:00
QRubberBand* _rubberBand = nullptr; // 原生橡皮筋
2026-04-15 18:17:16 +08:00
QList<PlotRectItem*> _selectionRectItems;
2026-05-13 11:29:36 +08:00
QwtPlotCurve* _fittedCurve = nullptr; // 显示拟合结果的曲线
2026-04-15 18:17:16 +08:00
// 存储当前显示的拟合曲线,用于清除
QList<QwtPlotCurve*> _fitCurves;
2026-04-15 18:17:16 +08:00
QString _historyFilePath;
PeakFitResult _lastFitResult;
2026-05-13 11:29:36 +08:00
arma::vec _lastFitParams; // 6个拟合参数 (A, delt, H, W, C, P)
double _lastXMin = 0.0, _lastXMax = 0.0;
bool _hasLastFit = false;
QString _workspace;
2026-05-13 11:29:36 +08:00
// 存储当前所有拟合结果(用于多曲线管理)
QList<CurrentFitRecord> _currentFitRecords;
2026-05-13 11:29:36 +08:00
// 历史记录列表
QList<PeakFitHistoryItem> _fitHistoryList;
2026-05-13 11:29:36 +08:00
// 当前悬停的框选区域
PlotRectItem* _hoveredRectItem = nullptr;
QList<DisplayedCurveRef> _displayedHistoryCurves;
QDialog* _historyDlg = nullptr; // 跟踪当前打开的峰拟合结果对话框
};
#endif // ENERGYCOUNTPEAKFITVIEW_H