EnergySpectrumAnalyer/src/EnergyCountPeakFitView/EnergyCountPeakFitView.h

166 lines
5.5 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> // 新增
#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; // 峰面积
};
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();
2026-05-13 11:29:36 +08:00
void saveCurrentFitToHistory(); // 保存当前拟合结果
void displayFitFromHistory(const PeakFitHistoryItem& item); // 显示历史拟合曲线
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);
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 onActionSaveCurrentFit();
void onActionShowFitHistory();
void onActionDeleteHoveredRect();
2026-05-13 11:29:36 +08:00
// 重新拟合当前悬停的框选区域
void onActionRefitCurrentRect();
2026-05-13 11:29:36 +08:00
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);
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*/);
// 根据拟合参数生成曲线
QwtPlotCurve* createFitCurve(const PeakFitResult& result, double xMin, double xMax, const QString& name);
QList<QwtPlotCurve*> createFitCurve(const PeakFitResult& result, arma::vec xVec);
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;
// [NEW] 最近一次拟合结果(用于手动保存)
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;
};
#endif // ENERGYCOUNTPEAKFITVIEW_H