新增能峰拟合分析框选
This commit is contained in:
parent
ceb970319e
commit
db797522e8
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QwtScaleDiv>
|
#include <QwtScaleDiv>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include "PlotRectItem.h"
|
||||||
|
|
||||||
|
|
||||||
EnergyCountPeakFitView::EnergyCountPeakFitView(QWidget *parent)
|
EnergyCountPeakFitView::EnergyCountPeakFitView(QWidget *parent)
|
||||||
|
|
@ -33,6 +34,8 @@ EnergyCountPeakFitView::EnergyCountPeakFitView(QWidget *parent)
|
||||||
EnergyCountPeakFitView::~EnergyCountPeakFitView()
|
EnergyCountPeakFitView::~EnergyCountPeakFitView()
|
||||||
{
|
{
|
||||||
LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName()));
|
LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName()));
|
||||||
|
delete _rubberBand;
|
||||||
|
clearAllSelectionRects();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnergyCountPeakFitView::InitViewWorkspace(const QString &project_name)
|
void EnergyCountPeakFitView::InitViewWorkspace(const QString &project_name)
|
||||||
|
|
@ -79,8 +82,14 @@ void EnergyCountPeakFitView::setupPlot()
|
||||||
// _plot->insertLegend(legend, QwtPlot::RightLegend);
|
// _plot->insertLegend(legend, QwtPlot::RightLegend);
|
||||||
|
|
||||||
_plot->SetAxisDragScale(QwtPlot::xBottom, true);
|
_plot->SetAxisDragScale(QwtPlot::xBottom, true);
|
||||||
|
|
||||||
|
|
||||||
_data_selector = new CustomQwtPlotXaxisSelector(_plot->canvas());
|
_data_selector = new CustomQwtPlotXaxisSelector(_plot->canvas());
|
||||||
_data_selector->setEnabled(false);
|
_data_selector->setEnabled(false);
|
||||||
|
|
||||||
|
// 启用鼠标追踪,并安装事件过滤器
|
||||||
|
_plot->canvas()->setMouseTracking(true);
|
||||||
|
_plot->canvas()->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnergyCountPeakFitView::setupMenu()
|
void EnergyCountPeakFitView::setupMenu()
|
||||||
|
|
@ -101,6 +110,13 @@ void EnergyCountPeakFitView::setupMenu()
|
||||||
QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置"));
|
QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置"));
|
||||||
action_plot_config->setObjectName("plot_config");
|
action_plot_config->setObjectName("plot_config");
|
||||||
connect(action_plot_config, &QAction::triggered, this, &EnergyCountPeakFitView::onActionPlotConfigure);
|
connect(action_plot_config, &QAction::triggered, this, &EnergyCountPeakFitView::onActionPlotConfigure);
|
||||||
|
|
||||||
|
this->_menu->addSeparator();
|
||||||
|
QAction* action_clear_rect = this->_menu->addAction(QStringLiteral(u"清除框选标记"));
|
||||||
|
connect(action_clear_rect, &QAction::triggered, this, &EnergyCountPeakFitView::clearAllSelectionRects);
|
||||||
|
|
||||||
|
QAction* action_hint = this->_menu->addAction(QStringLiteral(u"框选提示:按住 Ctrl 键并拖动左键"));
|
||||||
|
action_hint->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnergyCountPeakFitView::loadDataFromFile(const QString &data_name, const QString &filename)
|
void EnergyCountPeakFitView::loadDataFromFile(const QString &data_name, const QString &filename)
|
||||||
|
|
@ -209,4 +225,130 @@ void EnergyCountPeakFitView::onActionCurveShowSetting()
|
||||||
void EnergyCountPeakFitView::onActionPlotConfigure()
|
void EnergyCountPeakFitView::onActionPlotConfigure()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void EnergyCountPeakFitView::clearAllSelectionRects()
|
||||||
|
{
|
||||||
|
for (PlotRectItem* item : _selectionRectItems) {
|
||||||
|
if (item) {
|
||||||
|
item->detach();
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_selectionRectItems.clear();
|
||||||
|
_plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnergyCountPeakFitView::eventFilter(QObject* watched, QEvent* event)
|
||||||
|
{
|
||||||
|
if (watched == _plot->canvas()) {
|
||||||
|
QMouseEvent* me = static_cast<QMouseEvent*>(event);
|
||||||
|
|
||||||
|
// 按下 Ctrl+左键 开始框选
|
||||||
|
if (event->type() == QEvent::MouseButtonPress &&
|
||||||
|
me->button() == Qt::LeftButton &&
|
||||||
|
(me->modifiers() & Qt::ControlModifier)) {
|
||||||
|
startSelection(me->pos());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 移动时更新橡皮筋
|
||||||
|
else if (event->type() == QEvent::MouseMove && _isSelecting) {
|
||||||
|
updateSelection(me->pos());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 释放左键完成框选
|
||||||
|
else if (event->type() == QEvent::MouseButtonRelease &&
|
||||||
|
me->button() == Qt::LeftButton && _isSelecting) {
|
||||||
|
finishSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MeasureAnalysisView::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnergyCountPeakFitView::startSelection(const QPoint& pos)
|
||||||
|
{
|
||||||
|
_isSelecting = true;
|
||||||
|
_selectionStart = pos;
|
||||||
|
|
||||||
|
if (!_rubberBand) {
|
||||||
|
_rubberBand = new QRubberBand(QRubberBand::Rectangle, _plot->canvas());
|
||||||
|
}
|
||||||
|
_rubberBand->setGeometry(QRect(pos, QSize()));
|
||||||
|
_rubberBand->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnergyCountPeakFitView::updateSelection(const QPoint& pos)
|
||||||
|
{
|
||||||
|
if (!_rubberBand) return;
|
||||||
|
// 计算矩形(归一化)
|
||||||
|
QRect rect = QRect(_selectionStart, pos).normalized();
|
||||||
|
_rubberBand->setGeometry(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnergyCountPeakFitView::finishSelection()
|
||||||
|
{
|
||||||
|
if (_rubberBand) {
|
||||||
|
QRect finalRect = _rubberBand->geometry();
|
||||||
|
_rubberBand->hide();
|
||||||
|
if (finalRect.width() > 2 && finalRect.height() > 2) {
|
||||||
|
QRectF plotRect = pixelRectToPlotRect(finalRect);
|
||||||
|
addSelectionRect(plotRect); // 直接添加,不清除旧的
|
||||||
|
// TODO: 在此处添加峰拟合逻辑
|
||||||
|
// ========== 新增拟合逻辑 ==========
|
||||||
|
QList<QwtPlotCurve*> curves = _plot->GetCurveList();
|
||||||
|
if (curves.isEmpty()) return;
|
||||||
|
QwtPlotCurve* originalCurve = curves.first();
|
||||||
|
|
||||||
|
// 获取原始数据
|
||||||
|
QVector<double> origX, origY;
|
||||||
|
for (size_t i = 0; i < originalCurve->dataSize(); ++i) {
|
||||||
|
origX.push_back(originalCurve->sample(i).x());
|
||||||
|
origY.push_back(originalCurve->sample(i).y());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取框内的点
|
||||||
|
QVector<double> roiX, roiY;
|
||||||
|
for (int i = 0; i < origX.size(); ++i) {
|
||||||
|
if (origX[i] >= plotRect.left() && origX[i] <= plotRect.right() &&
|
||||||
|
origY[i] >= plotRect.bottom() && origY[i] <= plotRect.top()) {
|
||||||
|
roiX.push_back(origX[i]);
|
||||||
|
roiY.push_back(origY[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roiX.size() >= 3)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isSelecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF EnergyCountPeakFitView::pixelRectToPlotRect(const QRect& pixelRect) const
|
||||||
|
{
|
||||||
|
const QwtScaleMap xMap = _plot->canvasMap(QwtPlot::xBottom);
|
||||||
|
const QwtScaleMap yMap = _plot->canvasMap(QwtPlot::yLeft);
|
||||||
|
|
||||||
|
double x1 = xMap.invTransform(pixelRect.left());
|
||||||
|
double x2 = xMap.invTransform(pixelRect.right());
|
||||||
|
double y1 = yMap.invTransform(pixelRect.top());
|
||||||
|
double y2 = yMap.invTransform(pixelRect.bottom());
|
||||||
|
|
||||||
|
return QRectF(QPointF(x1, y1), QPointF(x2, y2)).normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnergyCountPeakFitView::addSelectionRect(const QRectF &plotRect)
|
||||||
|
{
|
||||||
|
PlotRectItem* rectItem = new PlotRectItem("Selection");
|
||||||
|
rectItem->setAxes(QwtPlot::xBottom, QwtPlot::yLeft);
|
||||||
|
rectItem->setRect(plotRect);
|
||||||
|
rectItem->attach(_plot);
|
||||||
|
_selectionRectItems.append(rectItem);
|
||||||
|
_plot->replot();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,17 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <MeasureAnalysisView.h>
|
#include <MeasureAnalysisView.h>
|
||||||
|
#include <QwtPlotPicker>
|
||||||
|
#include <QwtPickerDragRectMachine>
|
||||||
|
#include <QRubberBand> // 新增
|
||||||
|
#include <qwt_plot_shapeitem.h> // 新增
|
||||||
|
|
||||||
|
class PlotRectItem; // 前向声明
|
||||||
class QMenu;
|
class QMenu;
|
||||||
class CustomQwtPlot;
|
class CustomQwtPlot;
|
||||||
class CustomQwtPlotXaxisSelector;
|
class CustomQwtPlotXaxisSelector;
|
||||||
|
class QwtPlotPicker;
|
||||||
|
class QwtPlotCurve;
|
||||||
class EnergyCountPeakFitView : public MeasureAnalysisView
|
class EnergyCountPeakFitView : public MeasureAnalysisView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -27,12 +33,32 @@ private:
|
||||||
private slots:
|
private slots:
|
||||||
void onActionCurveShowSetting();
|
void onActionCurveShowSetting();
|
||||||
void onActionPlotConfigure();
|
void onActionPlotConfigure();
|
||||||
|
void clearAllSelectionRects();
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject* watched, QEvent* event) override; // 事件过滤器
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startSelection(const QPoint& pos);
|
||||||
|
void updateSelection(const QPoint& pos);
|
||||||
|
void finishSelection();
|
||||||
|
QRectF pixelRectToPlotRect(const QRect& pixelRect) const;
|
||||||
|
void addSelectionRect(const QRectF& plotRect);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CustomQwtPlot* _plot = nullptr;
|
CustomQwtPlot* _plot = nullptr;
|
||||||
QMenu* _menu = nullptr;
|
QMenu* _menu = nullptr;
|
||||||
QDialog* _curve_show_setting_dlg = nullptr;
|
QDialog* _curve_show_setting_dlg = nullptr;
|
||||||
CustomQwtPlotXaxisSelector* _data_selector = nullptr;
|
CustomQwtPlotXaxisSelector* _data_selector = nullptr;
|
||||||
|
// 手动框选状态
|
||||||
|
bool _isSelecting = false;
|
||||||
|
QPoint _selectionStart;
|
||||||
|
QRubberBand* _rubberBand = nullptr; // 原生橡皮筋
|
||||||
|
QList<PlotRectItem*> _selectionRectItems;
|
||||||
|
|
||||||
|
QwtPlotCurve* _fittedCurve = nullptr; // 显示拟合结果的曲线
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ENERGYCOUNTPEAKFITVIEW_H
|
#endif // ENERGYCOUNTPEAKFITVIEW_H
|
||||||
|
|
|
||||||
42
src/EnergyCountPeakFitView/PlotRectItem.cpp
Normal file
42
src/EnergyCountPeakFitView/PlotRectItem.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "PlotRectItem.h"
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QwtScaleMap>
|
||||||
|
PlotRectItem::PlotRectItem(const QString &title)
|
||||||
|
: QwtPlotItem() {
|
||||||
|
setTitle(title);
|
||||||
|
setZ(1000);
|
||||||
|
m_pen = QPen(Qt::red, 2, Qt::SolidLine);
|
||||||
|
m_brush = QBrush(QColor(255, 0, 0, 30));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotRectItem::setRect(const QRectF &rect) {
|
||||||
|
m_rect = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotRectItem::setPen(const QPen &pen) {
|
||||||
|
m_pen = pen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotRectItem::setBrush(const QBrush &brush) {
|
||||||
|
m_brush = brush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotRectItem::draw(QPainter *painter,
|
||||||
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||||
|
const QRectF &) const {
|
||||||
|
const int x1 = xMap.transform(m_rect.left());
|
||||||
|
const int x2 = xMap.transform(m_rect.right());
|
||||||
|
const int y1 = yMap.transform(m_rect.top());
|
||||||
|
const int y2 = yMap.transform(m_rect.bottom());
|
||||||
|
const QRect rect(QPoint(x1, y1), QPoint(x2, y2));
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
painter->setPen(m_pen);
|
||||||
|
painter->setBrush(m_brush);
|
||||||
|
painter->drawRect(rect);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF PlotRectItem::boundingRect() const {
|
||||||
|
return m_rect;
|
||||||
|
}
|
||||||
28
src/EnergyCountPeakFitView/PlotRectItem.h
Normal file
28
src/EnergyCountPeakFitView/PlotRectItem.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef PLOTRECTITEM_H
|
||||||
|
#define PLOTRECTITEM_H
|
||||||
|
|
||||||
|
#include <qwt_plot_item.h>
|
||||||
|
#include <QRectF>
|
||||||
|
#include <QString>
|
||||||
|
#include <QPen>
|
||||||
|
class PlotRectItem : public QwtPlotItem {
|
||||||
|
public:
|
||||||
|
PlotRectItem(const QString &title = QString());
|
||||||
|
|
||||||
|
void setRect(const QRectF &rect);
|
||||||
|
void setPen(const QPen &pen);
|
||||||
|
void setBrush(const QBrush &brush);
|
||||||
|
|
||||||
|
virtual void draw(QPainter *painter,
|
||||||
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||||
|
const QRectF &canvasRect) const override;
|
||||||
|
|
||||||
|
virtual QRectF boundingRect() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QRectF m_rect;
|
||||||
|
QPen m_pen;
|
||||||
|
QBrush m_brush;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PLOTRECTITEM_H
|
||||||
|
|
@ -74,6 +74,7 @@ SOURCES += \
|
||||||
DeviceParameterConfig/DeviceParameterConfig.cpp \
|
DeviceParameterConfig/DeviceParameterConfig.cpp \
|
||||||
DeviceParameterConfig/DeviceParameterConfigList.cpp \
|
DeviceParameterConfig/DeviceParameterConfigList.cpp \
|
||||||
EnergyCountPeakFitView/EnergyCountPeakFitView.cpp \
|
EnergyCountPeakFitView/EnergyCountPeakFitView.cpp \
|
||||||
|
EnergyCountPeakFitView/PlotRectItem.cpp \
|
||||||
EnergyCountPlotView/EnergyCountPlotView.cpp \
|
EnergyCountPlotView/EnergyCountPlotView.cpp \
|
||||||
EnergyScaleDataModel.cpp \
|
EnergyScaleDataModel.cpp \
|
||||||
EnergyScaleForm.cpp \
|
EnergyScaleForm.cpp \
|
||||||
|
|
@ -119,6 +120,7 @@ HEADERS += \
|
||||||
DeviceParameterConfig/DeviceParameterConfig.h \
|
DeviceParameterConfig/DeviceParameterConfig.h \
|
||||||
DeviceParameterConfig/DeviceParameterConfigList.h \
|
DeviceParameterConfig/DeviceParameterConfigList.h \
|
||||||
EnergyCountPeakFitView/EnergyCountPeakFitView.h \
|
EnergyCountPeakFitView/EnergyCountPeakFitView.h \
|
||||||
|
EnergyCountPeakFitView/PlotRectItem.h \
|
||||||
EnergyCountPlotView/EnergyCountPlotView.h \
|
EnergyCountPlotView/EnergyCountPlotView.h \
|
||||||
EnergyScaleDataModel.h \
|
EnergyScaleDataModel.h \
|
||||||
EnergyScaleForm.h \
|
EnergyScaleForm.h \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user