From 1ebb49e633b9e2dd5eb10d0b4de4989d03906df9 Mon Sep 17 00:00:00 2001
From: yuntang <123@qq.com>
Date: Fri, 9 May 2025 17:28:39 +0800
Subject: [PATCH] 2025-05-09T17:28:38
---
experiment_data/sample_data/~$锡.xlsx | Bin 0 -> 165 bytes
src/.idea/.gitignore | 8 +
src/.idea/.name | 1 +
src/.idea/editor.xml | 344 ++++++++++++++++++++++++++
src/.idea/misc.xml | 7 +
src/.idea/modules.xml | 8 +
src/.idea/src.iml | 2 +
src/.idea/vcs.xml | 6 +
src/AnalysisTool.pro | 4 +
src/data/pointcalculate.cpp | 30 +--
src/data/pointcalculate.h | 2 -
src/global.cpp | 104 ++++++++
src/global.h | 6 +-
src/ui/analysisoperationrecorder.cpp | 15 ++
src/ui/analysisoperationrecorder.h | 27 ++
src/ui/centralwidget.cpp | 316 +++++++++++------------
src/ui/centralwidget.h | 15 +-
src/ui/coefficientselectionform.cpp | 147 +----------
src/ui/coefficientselectionform.h | 5 -
src/ui/itemmanager.cpp | 72 ++++++
src/ui/itemmanager.h | 33 +++
21 files changed, 795 insertions(+), 357 deletions(-)
create mode 100644 experiment_data/sample_data/~$锡.xlsx
create mode 100644 src/.idea/.gitignore
create mode 100644 src/.idea/.name
create mode 100644 src/.idea/editor.xml
create mode 100644 src/.idea/misc.xml
create mode 100644 src/.idea/modules.xml
create mode 100644 src/.idea/src.iml
create mode 100644 src/.idea/vcs.xml
create mode 100644 src/ui/analysisoperationrecorder.cpp
create mode 100644 src/ui/analysisoperationrecorder.h
create mode 100644 src/ui/itemmanager.cpp
create mode 100644 src/ui/itemmanager.h
diff --git a/experiment_data/sample_data/~$锡.xlsx b/experiment_data/sample_data/~$锡.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..d4a5841882f71e1e9259c5c320e2b84832515279
GIT binary patch
literal 165
ZcmZQhOiETD9WXN_G9)o1Gbqpn0s!Zc4-)_Y
literal 0
HcmV?d00001
diff --git a/src/.idea/.gitignore b/src/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/src/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/src/.idea/.name b/src/.idea/.name
new file mode 100644
index 0000000..cf8f44e
--- /dev/null
+++ b/src/.idea/.name
@@ -0,0 +1 @@
+AnalysisTool
\ No newline at end of file
diff --git a/src/.idea/editor.xml b/src/.idea/editor.xml
new file mode 100644
index 0000000..25c6c37
--- /dev/null
+++ b/src/.idea/editor.xml
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/.idea/misc.xml b/src/.idea/misc.xml
new file mode 100644
index 0000000..0b76fe5
--- /dev/null
+++ b/src/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/.idea/modules.xml b/src/.idea/modules.xml
new file mode 100644
index 0000000..f669a0e
--- /dev/null
+++ b/src/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/.idea/src.iml b/src/.idea/src.iml
new file mode 100644
index 0000000..f08604b
--- /dev/null
+++ b/src/.idea/src.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/.idea/vcs.xml b/src/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/src/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AnalysisTool.pro b/src/AnalysisTool.pro
index 97bd6e8..226cfa3 100644
--- a/src/AnalysisTool.pro
+++ b/src/AnalysisTool.pro
@@ -28,9 +28,11 @@ SOURCES += \
global.cpp \
logger/logger.cpp \
ui/aboutform.cpp \
+ ui/analysisoperationrecorder.cpp \
ui/axissettingform.cpp \
ui/coefficientselectionform.cpp \
ui/enthalpydatacorrectionform.cpp \
+ ui/itemmanager.cpp \
ui/localcustomplot.cpp \
ui/printpreviewform.cpp \
ui/rightwidget.cpp \
@@ -62,9 +64,11 @@ HEADERS += \
defines.h \
logger/logger.h \
ui/aboutform.h \
+ ui/analysisoperationrecorder.h \
ui/axissettingform.h \
ui/coefficientselectionform.h \
ui/enthalpydatacorrectionform.h \
+ ui/itemmanager.h \
ui/localcustomplot.h \
ui/printpreviewform.h \
ui/rightwidget.h \
diff --git a/src/data/pointcalculate.cpp b/src/data/pointcalculate.cpp
index 72e98bb..cd733ce 100644
--- a/src/data/pointcalculate.cpp
+++ b/src/data/pointcalculate.cpp
@@ -259,9 +259,9 @@ float PointCalculate::calculateArea() {
float startTemp = _leftSelectedPoint.x();
- float c = Global::_enthalpyCoefficientVtr.at(0);
+ float a = Global::_enthalpyCoefficientVtr.at(0);
float b = Global::_enthalpyCoefficientVtr.at(1);
- float a = Global::_enthalpyCoefficientVtr.at(2);
+ float c = Global::_enthalpyCoefficientVtr.at(2);
coefficient = a * startTemp * startTemp +
b * startTemp +
@@ -663,29 +663,3 @@ double PointCalculate::obtainTimeValueBasedOnTemperatureValue(const double sampl
return targetValue;
}
-QPointF PointCalculate::onsetTemperaturePoint(const double x1, const double x2)
-{
- const double threshold = 0.1;
- QPointF targetPoint;
-
- QVector pointVtr = getPointVtrInXRange(x1,x2);
- for(int i = 3;i < pointVtr.size();i++){
- QPointF prePoint1 = pointVtr.at(i - 1);
- QPointF prePoint2 = pointVtr.at(i - 2);
- QPointF prePoint3 = pointVtr.at(i - 3);
-
- QPointF currentPoint = pointVtr.at(i);
-
- if(std::abs(prePoint1.y() - currentPoint.y()) > threshold){
- targetPoint = pointVtr.at(i - 3);
- }
- if(std::abs(prePoint2.y() - currentPoint.y()) > threshold){
- targetPoint = pointVtr.at(i - 3);
- }
- if(std::abs(prePoint3.y() - currentPoint.y()) > threshold){
- targetPoint = pointVtr.at(i - 3);
- }
- }
-
- return targetPoint;
-}
diff --git a/src/data/pointcalculate.h b/src/data/pointcalculate.h
index 70de9fa..b646738 100644
--- a/src/data/pointcalculate.h
+++ b/src/data/pointcalculate.h
@@ -50,8 +50,6 @@ double calculateSlope(double x1, double y1, double x2, double y2) ;
QVector findInflectionPoints(const QVector& x, const QVector& y) ;
QMap calculateTangentLine(const QVector& x, const QVector& y) ;
-QPointF onsetTemperaturePoint(const double x1,const double x2);
-
//private
void updateStartEndPoint();
QPair calculateMaxDiffPointLeft();
diff --git a/src/global.cpp b/src/global.cpp
index b736d78..914f7b4 100644
--- a/src/global.cpp
+++ b/src/global.cpp
@@ -1,3 +1,6 @@
+#include
+#include
+
#include "global.h"
namespace Global {
@@ -20,6 +23,107 @@ QString converDoubleToStr(const double num)
return QString::number(num,'f',3);
}
+void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[])
+{
+ if (n < 3) {
+ throw std::invalid_argument("At least 3 data points are required for quadratic fitting");
+ }
+
+ double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0;
+ double sum_y = 0, sum_xy = 0, sum_x2y = 0;
+
+ // 计算各项累加和
+ for (int i = 0; i < n; ++i) {
+ double xi = x[i];
+ double xi2 = xi * xi;
+ double xi3 = xi2 * xi;
+ double xi4 = xi3 * xi;
+ double yi = y[i];
+
+ sum_x += xi;
+ sum_x2 += xi2;
+ sum_x3 += xi3;
+ sum_x4 += xi4;
+ sum_y += yi;
+ sum_xy += xi * yi;
+ sum_x2y += xi2 * yi;
+ }
+
+ // 构建正规方程组的增广矩阵
+ double matrix[3][4] = {
+ {sum_x4, sum_x3, sum_x2, sum_x2y}, // 对应方程: a*Σx⁴ + b*Σx³ + c*Σx² = Σx²y
+ {sum_x3, sum_x2, sum_x, sum_xy}, // 对应方程: a*Σx³ + b*Σx² + c*Σx = Σxy
+ {sum_x2, sum_x, static_cast(n), sum_y} // 对应方程: a*Σx² + b*Σx + c*n = Σy
+ };
+
+ // 高斯消元法解方程组
+ for (int i = 0; i < 3; ++i) {
+ // 部分主元选择
+ int maxRow = i;
+ for (int k = i + 1; k < 3; ++k) {
+ if (std::abs(matrix[k][i]) > std::abs(matrix[maxRow][i])) {
+ maxRow = k;
+ }
+ }
+
+ // 交换行
+ for (int k = i; k < 4; ++k) {
+ std::swap(matrix[i][k], matrix[maxRow][k]);
+ }
+
+ // 消元
+ for (int k = i + 1; k < 3; ++k) {
+ double factor = matrix[k][i] / matrix[i][i];
+ for (int j = i; j < 4; ++j) {
+ matrix[k][j] -= factor * matrix[i][j];
+ }
+ }
+ }
+
+ // 回代求解
+ coeff[2] = matrix[2][3] / matrix[2][2]; // c
+ coeff[1] = (matrix[1][3] - matrix[1][2] * coeff[2]) / matrix[1][1]; // b
+ coeff[0] = (matrix[0][3] - matrix[0][2] * coeff[2] - matrix[0][1] * coeff[1]) / matrix[0][0]; // a
+}
+
+// 计算一元一次函数在给定区间内开始变成负值的点
+double findNegativeStartPoint(double m, double b, double start, double end) {
+ // 处理斜率为零的情况
+ if (m == 0) {
+ // 当斜率为 0 时,函数值为常数 b
+ if (b < 0) {
+ return start; // 若 b 为负,函数在区间起始点就为负
+ } else {
+ return std::numeric_limits::infinity(); // 若 b 非负,函数在区间内不会变负
+ }
+ }
+
+ // 计算零点
+ double zeroPoint = -b / m;
+
+ // 检查零点是否在给定区间内
+ if (zeroPoint >= start && zeroPoint <= end) {
+ return zeroPoint; // 零点在区间内,函数在此点开始变负
+ }
+
+ // 根据斜率正负判断函数单调性,进而判断函数在区间内是否会变负
+ if (m > 0) {
+ // 斜率大于 0,函数单调递增
+ if (m * start + b < 0) {
+ return start; // 起始点函数值为负,函数在起始点就为负
+ }
+ } else {
+ // 斜率小于 0,函数单调递减
+ if (m * end + b < 0) {
+ return end; // 结束点函数值为负,函数在结束点开始为负
+ }
+ }
+
+ // 函数在区间内不会变负
+ return std::numeric_limits::infinity();
+}
+
+
}
diff --git a/src/global.h b/src/global.h
index 6fa5bed..cff6340 100644
--- a/src/global.h
+++ b/src/global.h
@@ -8,7 +8,7 @@
#include "protocol.h"
namespace Global {
-const QString ConSoftVersion = "0.9.7";
+const QString ConSoftVersion = "0.9.7.1";
const QString ExperimentDirPath = QDir::currentPath()+"/../experiment_data";
@@ -109,8 +109,10 @@ extern bool _displayTimeValue;
// common func
QString converDoubleToStr(const double);
-}
+void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[]);
+double findNegativeStartPoint(double m, double b, double start, double end);
+}
#if 0
class Global:public QObject
{
diff --git a/src/ui/analysisoperationrecorder.cpp b/src/ui/analysisoperationrecorder.cpp
new file mode 100644
index 0000000..b14441d
--- /dev/null
+++ b/src/ui/analysisoperationrecorder.cpp
@@ -0,0 +1,15 @@
+#include "analysisoperationrecorder.h"
+
+namespace AnalysisOperationRecorder {
+void addAnalysisOperation(const AnalysisOperation ao)
+{
+ _ananlysisOperationVtr.push_back(ao);
+}
+
+void removeTheLastAnalysisOperation()
+{
+ if (!_ananlysisOperationVtr.isEmpty()) {
+ _ananlysisOperationVtr.removeLast();
+ }
+}
+}
diff --git a/src/ui/analysisoperationrecorder.h b/src/ui/analysisoperationrecorder.h
new file mode 100644
index 0000000..1f5eed6
--- /dev/null
+++ b/src/ui/analysisoperationrecorder.h
@@ -0,0 +1,27 @@
+#ifndef ANALYSISOPERATIONRECORDER_H
+#define ANALYSISOPERATIONRECORDER_H
+
+namespace AnalysisOperationRecorder {
+enum AnalysisMode{
+ Null,
+ NumericalLabel,
+ StartPoint,
+ StopPoint,
+ PeakSynthesisAnalysis,
+ GlassTransition,
+ OnsetTemperaturePoint,
+ EndsetTemperaturePoint
+};
+struct AnalysisOperation{
+ AnalysisMode mode;
+ QPointF point;
+ QString str;
+};
+
+QVector _ananlysisOperationVtr;
+void addAnalysisOperation(const AnalysisOperation);
+void removeTheLastAnalysisOperation();
+
+}
+
+#endif // ANALYSISOPERATIONRECORDER_H
diff --git a/src/ui/centralwidget.cpp b/src/ui/centralwidget.cpp
index a7cdb88..c1d9fbc 100644
--- a/src/ui/centralwidget.cpp
+++ b/src/ui/centralwidget.cpp
@@ -5,11 +5,13 @@
#include
#include
+#include "analysisoperationrecorder.h"
#include "centralwidget.h"
#include "filemanager.h"
#include "pointcalculate.h"
#include "logger.h"
#include "xlsxhandler.h"
+#include "itemmanager.h"
CentralWidget::CentralWidget(QWidget *parent)
: QWidget(parent)
@@ -246,7 +248,7 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &filePath)
return;
}
- qDebug() << "slotRecvAnalysisFileName" << filePath;
+ // qDebug() << "slotRecvAnalysisFileName:" << filePath;
Global::CurveFileData cfd;
if(XlsxHandler::readFile(filePath,cfd) != 0){
@@ -304,13 +306,22 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &filePath)
void CentralWidget::slotAnalysisSettingApply()
{
+ double x1 = _line1->point1->coords().x();
+ double x2 = _line2->point1->coords().x();
+
+ if(_x1Record == x1 && _x2Record == x2){
+ return;
+ }else{
+ _x1Record = x1;
+ _x2Record = x2;
+ }
+ //
switch (_analysisMode) {
case AnalysisMode::NumericalLabel:
{
- QPointF selectPoint = PointCalculate::getClosestPointByX(
- _line1->point1->coords().x());
+ QPointF selectPoint = PointCalculate::getClosestPointByX(x1);
- logde<<"lin1 x:"<<_line1->point1->coords().x();
+// logde<<"lin1 x:"<parent(), "warnning", "曲线选择错误.");
@@ -324,8 +335,6 @@ void CentralWidget::slotAnalysisSettingApply()
}
case AnalysisMode::StartPoint:
case AnalysisMode::StopPoint:{
- double x1 = _line1->point1->coords().x();
- double x2 = _line2->point1->coords().x();
PointCalculate::setRegionPointX(x1,x2);
QPair startEndPointPair =
@@ -343,9 +352,6 @@ void CentralWidget::slotAnalysisSettingApply()
}
case AnalysisMode::PeakSynthesisAnalysis:
{
- double x1 = _line1->point1->coords().x();
- double x2 = _line2->point1->coords().x();
-
fillGraph(x1,x2);
PointCalculate::setRegionPointX(x1,x2);
@@ -359,14 +365,14 @@ void CentralWidget::slotAnalysisSettingApply()
}
}
}
- logde<<"sample weight:"< startEndPointPair =
PointCalculate::calculateStartAndEndPoint();
@@ -396,21 +402,22 @@ void CentralWidget::slotAnalysisSettingApply()
}
case AnalysisMode::GlassTransition:
{
- // glassTransitionHandle();
- glassTransitionHandle2();
- //
+ glassTransitionHandle(x1,x2);
+
break;
}
case AnalysisMode::OnsetTemperaturePoint:{
- double x1 = _line1->point1->coords().x();
- double x2 = _line2->point1->coords().x();
-
- QPointF point = PointCalculate::onsetTemperaturePoint(x1,x2);
+#if 0
+ QPointF point = OnsetTemperaturePointHandle(x1,x2);
QString str = QString::number(point.y(),'f',3);
drawText(point,str);
+#endif
+ QPointF point = OnsetTemperaturePointHandle(x1,x2);
+ QString str = QString::number(point.x(),'f',3);
+ drawText(point,str);
break;
}
@@ -424,6 +431,8 @@ void CentralWidget::slotAnalysisSettingApply()
void CentralWidget::slotAnalysisSettingConfirm()
{
+ ItemManager::confirm();
+
slotAnalysisSettingApply();
setAnalysisMode(CentralWidget::AnalysisMode::Null);
@@ -437,6 +446,9 @@ void CentralWidget::slotAnalysisSettingConfirm()
void CentralWidget::slotAnalysisSettingUndo()
{
clearData(ClearDataMode::Undo);
+
+ _x1Record = 0.0;
+ _x2Record = 0.0;
}
void CentralWidget::slotAnalysisSettingCancel()
@@ -547,128 +559,10 @@ void CentralWidget::contextMenuEvent(QContextMenuEvent *event)
emit sigContextMenuShow(point);
}
-void CentralWidget::glassTransitionHandle()
+void CentralWidget::glassTransitionHandle(const double x1,const double x2)
{
- QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x());
- QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x());
-
- logde<<"point1:"<point1->setCoords(point1.x() - 5,point1.y());
- line1->point2->setCoords(point1.x() + 5,point1.y());
- line1->setPen(QPen(Qt::darkRed));
- line1->setSelectable(false);
- line1->setVisible(true);
-
- QCPItemStraightLine *line2 = new QCPItemStraightLine(_customPlot);
- line2->point1->setCoords(point2.x() - 5,point2.y());
- line2->point2->setCoords(point2.x() + 5,point2.y());
- line2->setPen(QPen(Qt::darkGreen));
- line2->setSelectable(false);
- line2->setVisible(true);
-
- _customPlot->replot();
-#endif
- //
- PointCalculate::Line lineStrc1,lineStrc2,tangetLineStrc;
-
- lineStrc1.slope = 0.0;
- lineStrc1.intercept = point1.y();
-
- lineStrc2.slope = 0.0;
- lineStrc2.intercept = point2.y();
-
- QPair tangentLinePair = PointCalculate::getCurveInflectionPointTangent(point1.x(),point2.x());
- tangetLineStrc.slope = tangentLinePair.first;
- tangetLineStrc.intercept = tangentLinePair.second;
-
- QPointF intersection1 = PointCalculate::getIntersection(tangetLineStrc,lineStrc1);
- QPointF intersection2 = PointCalculate::getIntersection(tangetLineStrc,lineStrc2);
-
- // logde<<"intersection1 x:"< xVtr,yVtr;
- xVtr.push_back(intersection1.x());
- xVtr.push_back(point1.x());
-
- yVtr.push_back(intersection1.y());
- yVtr.push_back(point1.y());
-
- QCPGraph *lineGraph1 = _customPlot->addGraph();
- lineGraph1->setData(xVtr, yVtr);
- _customPlot->replot();
-
- ///line2
- QVector xVtr2,yVtr2;
- xVtr2.push_back(intersection2.x());
- xVtr2.push_back(point2.x());
-
- yVtr2.push_back(intersection2.y());
- yVtr2.push_back(point2.y());
-
- QCPGraph *lineGraph2 = _customPlot->addGraph();
- lineGraph2->setData(xVtr2, yVtr2);
- _customPlot->replot();
-
- //draw text
- drawText(averagePoint,str);
-
- _customPlot->replot();
-
-
-#if 0
- // 创建一个圆形绘图项
- QCPItemEllipse *circle = new QCPItemEllipse(_customPlot);
- // _customPlot->addItem(circle);
-
- // 设置圆形的位置和大小
- circle->topLeft->setCoords(-5, 5);
- circle->bottomRight->setCoords(5, -5);
-
- // 设置圆形的填充和边框颜色
- circle->setBrush(QBrush(Qt::cyan));
- circle->setPen(QPen(Qt::blue));
-#endif
-
-#if 0
- QCPItemStraightLine *line3 = new QCPItemStraightLine(_customPlot);
- line3->point1->setCoords(averagePoint.x() + 1,averagePoint.y() + 1);
- line3->point2->setCoords(averagePoint.x() - 1,averagePoint.y() - 1);
- line3->setPen(QPen(Qt::black));
- line3->setSelectable(false);
- line3->setVisible(true);
-
- _customPlot->replot();
-#endif
-}
-
-void CentralWidget::glassTransitionHandle2()
-{
- QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x());
- QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x());
+ QPointF point1 = PointCalculate::getClosestPointByX(x1);
+ QPointF point2 = PointCalculate::getClosestPointByX(x2);
logde<<"point1:"<addGraph();
lineGraph1->setData(xVtr, yVtr);
+
+ ItemManager::addTemporaryQCPGraph(lineGraph1);
+
QPen pen;
pen.setColor(Qt::darkGreen);
lineGraph1->setPen(pen);
@@ -728,12 +625,14 @@ void CentralWidget::glassTransitionHandle2()
lineGraph2->setData(xVtr2, yVtr2);
lineGraph2->setPen(pen);
+ ItemManager::addTemporaryQCPGraph(lineGraph2);
+
_customPlot->replot();
#endif
// inflection point.
QVector originalPointVtr = PointCalculate::getPointVtrInXRange(point1.x(),point2.x());
- // QVector pointVtr = PointCalculate::movingAveragePoint(originalPointVtr,3);
+
QVector pointVtr = originalPointVtr;
xVtr.clear();
@@ -748,6 +647,7 @@ void CentralWidget::glassTransitionHandle2()
double targetX = 0.0;
PointCalculate::Line targetLine;
double maxSlopeAbs = 0.0; // 初始化最大斜率绝对值为0
+
#if 0
for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) {
if (std::fabs(it.value().slope) > maxSlopeAbs) {
@@ -758,6 +658,7 @@ void CentralWidget::glassTransitionHandle2()
}
}
#endif
+
// new method
for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) {
if (std::fabs(it.value().slope) > maxSlopeAbs) {
@@ -801,6 +702,7 @@ void CentralWidget::glassTransitionHandle2()
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
#endif
+
#if 1
xVtr.push_back(intersection1.x());
yVtr.push_back(intersection1.y());
@@ -812,6 +714,8 @@ void CentralWidget::glassTransitionHandle2()
QCPGraph *lineGraph3 = _customPlot->addGraph();
lineGraph3->setData(xVtr, yVtr);
lineGraph3->setPen(pen);
+
+ ItemManager::addTemporaryQCPGraph(lineGraph3);
#endif
_customPlot->replot();
@@ -853,6 +757,32 @@ PointCalculate::Line CentralWidget::calculateLinearRegression(const QVector rowPointVtr = PointCalculate::getPointVtrInXRange(x1,x2);
+
+ QVector pointVtr = PointCalculate::movingAveragePoint(rowPointVtr,5);
+
+ QVector xVtr,yVtr;
+ for (QPointF &point : pointVtr) {
+ xVtr.push_back(point.x());
+ yVtr.push_back(point.y());
+ }
+
+ double coeff[3] = {0};
+ Global::quadraticLeastSquaresFit(xVtr.data(),yVtr.data(),xVtr.size(),coeff);
+
+ // derivative
+ double a = coeff[0] * 2;
+ double b = coeff[1];
+
+ double targetX = Global::findNegativeStartPoint(a,b,pointVtr.first().x(),pointVtr.last().x());
+ logde<<"traget x:"<& points, double& a, double& b, double& c) {
int n = points.size();
@@ -956,6 +886,8 @@ void CentralWidget::drawText(const QPointF point, const QString text)
textLabel->setSelectedFont(font);
textLabel->setSelectable(true); // 设置为可选
+ ItemManager::addTemporaryQCPItemText(textLabel);
+
// 创建指向点的线段(QCPItemLine)
QCPItemLine *arrow = new QCPItemLine(_customPlot);
arrow->start->setParentAnchor(textLabel->left); // 线段起点绑定到标注文字底部
@@ -963,6 +895,8 @@ void CentralWidget::drawText(const QPointF point, const QString text)
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
arrow->setPen(QPen(Qt::red, 1));
+ ItemManager::addTemporaryQCPItemLine(arrow);
+
// 重绘图表以显示文本标签和箭头
_customPlot->replot();
}
@@ -981,7 +915,6 @@ void CentralWidget::fillGraph(const double x1, const double x2)
QCPGraph *mainGraph = _customPlot->addGraph();
mainGraph->setData(xVtr, yVtr);
-
mainGraph->setPen(QPen(Qt::red, 1));
QVector curveDataVtr =
@@ -995,55 +928,102 @@ void CentralWidget::fillGraph(const double x1, const double x2)
fillX<setData(fillX, fillY);
fillGraph->setBrush(QBrush(Qt::green, Qt::SolidPattern));
fillGraph->setChannelFillGraph(mainGraph);
+ ItemManager::addTemporaryQCPGraph(mainGraph);
+ ItemManager::addTemporaryQCPGraph(fillGraph);
+
_customPlot->replot();
}
void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
{
if(mode == ClearDataMode::All){
- // Clear the data of graph.
-
- for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) {
- QCPAbstractPlottable* plottable = _customPlot->plottable(i);
- if (auto curve = dynamic_cast(plottable)) {
- _customPlot->removePlottable(curve);
- }
- }
-
// Clear data.
Global::_curveExperimentDataVtr.clear();
// Set lines visiable false.
_line1->setVisible(false);
_line2->setVisible(false);
- }
-#if 0
- // Clear graph on plot.
- for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
- QCPGraph *graph = _customPlot->graph(i);
- _customPlot->removeGraph(graph);
- }
- _currentCurve = nullptr;
-#endif
+ _currentCurve = nullptr;
- // Delete items.
- QList itemsToKeep;
- itemsToKeep << _line1 << _line2;
+ //ui
+ // Clear the data of graph.
+ for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) {
+ QCPAbstractPlottable* plottable = _customPlot->plottable(i);
+ if (auto curve = dynamic_cast(plottable)) {
+ _customPlot->removePlottable(curve);
- for (int i = _customPlot->itemCount() - 1; i >= 0; --i) {
- QCPAbstractItem *item = _customPlot->item(i);
- if (!itemsToKeep.contains(item)) {
- _customPlot->removeItem(item);
+ ItemManager::removeItem(curve);
+ }
+ }
+
+ // Clear graph on plot.
+ for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
+ QCPGraph *graph = _customPlot->graph(i);
+ _customPlot->removeGraph(graph);
+
+ ItemManager::removeItem(graph);
+ }
+
+ // Delete items.
+ QList itemsToKeep;
+ itemsToKeep << _line1 << _line2;
+
+ for (int i = _customPlot->itemCount() - 1; i >= 0; --i) {
+ QCPAbstractItem *item = _customPlot->item(i);
+ if (!itemsToKeep.contains(item)) {
+ _customPlot->removeItem(item);
+
+ ItemManager::removeItem(item);
+ }
+ }
+ }else if(mode == ClearDataMode::Undo){
+ // Clear the data of graph.
+ for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) {
+ QCPAbstractPlottable* plottable = _customPlot->plottable(i);
+ if (auto curve = dynamic_cast(plottable)) {
+ logde<<"clear data,curve object Name:"<objectName().toStdString();
+ if(curve->objectName() == ItemManager::TemporaryStr){
+ _customPlot->removePlottable(curve);
+
+ ItemManager::removeItem(curve);
+ }
+ }
+ }
+
+ // Clear graph on plot.
+ for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
+ QCPGraph *graph = _customPlot->graph(i);
+ logde<<"clear data,graph object Name:"<objectName().toStdString();
+ if(graph && graph->objectName() == ItemManager::TemporaryStr){
+ _customPlot->removeGraph(graph);
+
+ ItemManager::removeItem(graph);
+ }
+ }
+
+ // Delete items.
+ QList itemsToKeep;
+ itemsToKeep << _line1 << _line2;
+
+ for (int i = _customPlot->itemCount() - 1; i >= 0; --i) {
+ QCPAbstractItem *item = _customPlot->item(i);
+ logde<<"item data,graph object Name:"<objectName().toStdString();
+ if(item && !itemsToKeep.contains(item)
+ && item->objectName() == ItemManager::TemporaryStr){
+ _customPlot->removeItem(item);
+
+ ItemManager::removeItem(item);
+ }
}
}
- // 重绘图表以显示更改
_customPlot->replot();
}
diff --git a/src/ui/centralwidget.h b/src/ui/centralwidget.h
index f90d050..44559ca 100644
--- a/src/ui/centralwidget.h
+++ b/src/ui/centralwidget.h
@@ -75,13 +75,13 @@ protected:
void timerEvent(QTimerEvent* event);
void contextMenuEvent(QContextMenuEvent *event);
private:
- void glassTransitionHandle();
-
- void glassTransitionHandle2();
+ void glassTransitionHandle(const double x1,const double x2);
void quadraticFit(const QVector& points, double& a, double& b, double& c);
double derivativeAt(const double a, const double b, const double x);
PointCalculate::Line calculateLinearRegression(const QVector& x, const QVector& y);
+ QPointF OnsetTemperaturePointHandle(const double x1,const double x2);
+
void setEventHandlerEnable(const bool);
QPointF getTheCoordinatesOfTheTextBox(const QPointF point);
void drawText(const QPointF,const QString);
@@ -92,20 +92,19 @@ private:
Undo
};
void clearData(const ClearDataMode);
+
private:
AnalysisMode _analysisMode;
LocalCustomPlot *_customPlot;
- // QCustomPlot*_customPlot;
QCPCurve *_currentCurve;
- // QVector _curveVtr;
- // QCPGraph* _currentGraph;
- // QVector _graphVtr;
EventHandler* _eventHandler;
QCPItemStraightLine *_line1,*_line2;
- // QVector _dataVtr;
QVector _lineVtr;
AxisMode _axisMode;
QVector _analysisFilePathVtr;
+
+ double _x1Record;
+ double _x2Record;
};
#endif // CENTRALWIDGET_H
diff --git a/src/ui/coefficientselectionform.cpp b/src/ui/coefficientselectionform.cpp
index ae44908..9e39a97 100644
--- a/src/ui/coefficientselectionform.cpp
+++ b/src/ui/coefficientselectionform.cpp
@@ -89,7 +89,7 @@ void CoefficientSelectionForm::on_pushButtonConfirm_clicked()
}
double coeff[3] = {0};
- quadraticLeastSquaresFit(xVtr.data(),yVtr.data(),xVtr.size(),coeff);
+ Global::quadraticLeastSquaresFit(xVtr.data(),yVtr.data(),xVtr.size(),coeff);
#if 0
std::cout << "Fitted quadratic polynomial: y = "
@@ -105,9 +105,9 @@ void CoefficientSelectionForm::on_pushButtonConfirm_clicked()
Global::_enthalpyCoefficientEnableFlag = true;
Global::_enthalpyCoefficientVtr.clear();
- Global::_enthalpyCoefficientVtr.push_back(coeff[2]);
- Global::_enthalpyCoefficientVtr.push_back(coeff[1]);
Global::_enthalpyCoefficientVtr.push_back(coeff[0]);
+ Global::_enthalpyCoefficientVtr.push_back(coeff[1]);
+ Global::_enthalpyCoefficientVtr.push_back(coeff[2]);
}
hide();
@@ -128,67 +128,7 @@ void CoefficientSelectionForm::on_pushButtonExit_clicked()
hide();
}
-void CoefficientSelectionForm::quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[]) {
- if (n < 3) {
- throw std::invalid_argument("At least 3 data points are required for quadratic fitting");
- }
- double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0;
- double sum_y = 0, sum_xy = 0, sum_x2y = 0;
-
- // 计算各项累加和
- for (int i = 0; i < n; ++i) {
- double xi = x[i];
- double xi2 = xi * xi;
- double xi3 = xi2 * xi;
- double xi4 = xi3 * xi;
- double yi = y[i];
-
- sum_x += xi;
- sum_x2 += xi2;
- sum_x3 += xi3;
- sum_x4 += xi4;
- sum_y += yi;
- sum_xy += xi * yi;
- sum_x2y += xi2 * yi;
- }
-
- // 构建正规方程组的增广矩阵
- double matrix[3][4] = {
- {sum_x4, sum_x3, sum_x2, sum_x2y}, // 对应方程: a*Σx⁴ + b*Σx³ + c*Σx² = Σx²y
- {sum_x3, sum_x2, sum_x, sum_xy}, // 对应方程: a*Σx³ + b*Σx² + c*Σx = Σxy
- {sum_x2, sum_x, static_cast(n), sum_y} // 对应方程: a*Σx² + b*Σx + c*n = Σy
- };
-
- // 高斯消元法解方程组
- for (int i = 0; i < 3; ++i) {
- // 部分主元选择
- int maxRow = i;
- for (int k = i + 1; k < 3; ++k) {
- if (std::abs(matrix[k][i]) > std::abs(matrix[maxRow][i])) {
- maxRow = k;
- }
- }
-
- // 交换行
- for (int k = i; k < 4; ++k) {
- std::swap(matrix[i][k], matrix[maxRow][k]);
- }
-
- // 消元
- for (int k = i + 1; k < 3; ++k) {
- double factor = matrix[k][i] / matrix[i][i];
- for (int j = i; j < 4; ++j) {
- matrix[k][j] -= factor * matrix[i][j];
- }
- }
- }
-
- // 回代求解
- coeff[2] = matrix[2][3] / matrix[2][2]; // c
- coeff[1] = (matrix[1][3] - matrix[1][2] * coeff[2]) / matrix[1][1]; // b
- coeff[0] = (matrix[0][3] - matrix[0][2] * coeff[2] - matrix[0][1] * coeff[1]) / matrix[0][0]; // a
-}
void CoefficientSelectionForm::on_pushButtonSelectFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(
@@ -256,84 +196,3 @@ void CoefficientSelectionForm::on_radioButtonMultiPointCoefficient_toggled(bool
}
#endif
}
-
-void CoefficientSelectionForm::cubicLeastSquaresFit(
- double x[], double y[], int n, double coeff[])
-{
- int i, j, k;
- double atemp[3] = {0}; // 存储x^0, x^1, x^2的和
- double b[3] = {0}; // 右侧向量
-
- // 计算各次幂的和
- for (i = 0; i < n; i++) {
- double xi = x[i];
- double xi_pow2 = xi * xi; // x^2
-
- // 累加atemp[0]到atemp[2]
- atemp[0] += 1; // x^0的和等于数据点个数
- atemp[1] += xi;
- atemp[2] += xi_pow2;
-
- // 计算右侧向量b
- double yi = y[i];
- b[0] += yi;
- b[1] += yi * xi;
- b[2] += yi * xi_pow2;
- }
-
- // 构建法方程矩阵
- double a[3][3];
- a[0][0] = atemp[0];
- a[0][1] = atemp[1];
- a[0][2] = atemp[2];
- a[1][0] = atemp[1];
- a[1][1] = atemp[2];
- a[1][2] = 0;
- a[2][0] = atemp[2];
- a[2][1] = 0;
- a[2][2] = 0;
-
- // 高斯列主元消元法
- for (k = 0; k < 2; k++) { // 消去第k列
- // 寻找主元行
- int max_row = k;
- double max_val = fabs(a[k][k]);
- for (i = k + 1; i < 3; i++) {
- if (fabs(a[i][k]) > max_val) {
- max_val = fabs(a[i][k]);
- max_row = i;
- }
- }
-
- // 交换行
- if (max_row != k) {
- for (j = k; j < 3; j++) {
- double temp = a[k][j];
- a[k][j] = a[max_row][j];
- a[max_row][j] = temp;
- }
- double temp_b = b[k];
- b[k] = b[max_row];
- b[max_row] = temp_b;
- }
-
- // 消元
- for (i = k + 1; i < 3; i++) {
- double factor = a[i][k] / a[k][k];
- for (j = k; j < 3; j++) {
- a[i][j] -= factor * a[k][j];
- }
- b[i] -= factor * b[k];
- }
- }
-
- // 回代求解
- coeff[2] = b[2] / a[2][2];
- for (i = 1; i >= 0; i--) {
- double sum = 0.0;
- for (j = i + 1; j < 3; j++) {
- sum += a[i][j] * coeff[j];
- }
- coeff[i] = (b[i] - sum) / a[i][i];
- }
-}
diff --git a/src/ui/coefficientselectionform.h b/src/ui/coefficientselectionform.h
index a56dad1..604091f 100644
--- a/src/ui/coefficientselectionform.h
+++ b/src/ui/coefficientselectionform.h
@@ -26,11 +26,6 @@ private slots:
void on_pushButtonConfirm_clicked();
void on_pushButtonExit_clicked();
private:
- // 立方拟合
- void cubicLeastSquaresFit(double x[], double y[], int n, double coeff[4]);
- // 平方拟合
- void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[]);
-
QString _jsonStr;
Ui::CoefficientSelectionForm *ui;
float _instrumentCoefficient;
diff --git a/src/ui/itemmanager.cpp b/src/ui/itemmanager.cpp
new file mode 100644
index 0000000..bd17257
--- /dev/null
+++ b/src/ui/itemmanager.cpp
@@ -0,0 +1,72 @@
+#include "itemmanager.h"
+
+namespace ItemManager {
+QVector _QCPItemTextVtr;
+QVector _QCPItemLineVtr;
+QVector _QCPGraphVtr;
+
+void addTemporaryQCPItemText(QCPItemText *item)
+{
+ item->setObjectName(TemporaryStr);
+ _QCPItemTextVtr.push_back(item);
+}
+
+void addTemporaryQCPItemLine(QCPItemLine *item)
+{
+ item->setObjectName(TemporaryStr);
+ _QCPItemLineVtr.push_back(item);
+}
+
+void confirm()
+{
+ for(QCPItemText *item:_QCPItemTextVtr){
+ item->setObjectName(ConfirmStr);
+ }
+
+ for(QCPItemLine *item:_QCPItemLineVtr){
+ item->setObjectName(ConfirmStr);
+ }
+
+ for(QCPGraph *graph:_QCPGraphVtr){
+ graph->setObjectName(ConfirmStr);
+ }
+}
+
+void addTemporaryQCPGraph(QCPGraph * graph)
+{
+ graph->setObjectName(TemporaryStr);
+ _QCPGraphVtr.push_back(graph);
+}
+
+void removeItem(QObject *obj)
+{
+ for (int i = _QCPItemTextVtr.size() - 1; i >= 0; --i) {
+ QCPItemText *item = _QCPItemTextVtr[i];
+ if (item == obj) {
+ _QCPItemTextVtr.remove(i);
+ return;
+ }
+ }
+
+ for (int i = _QCPItemLineVtr.size() - 1; i >= 0; --i) {
+ QCPItemLine *item = _QCPItemLineVtr[i];
+ if (item == obj) {
+ _QCPItemLineVtr.remove(i);
+ return;
+ }
+ }
+
+ for (int i = _QCPGraphVtr.size() - 1; i >= 0; --i) {
+ QCPGraph *item = _QCPGraphVtr[i];
+ if (item == obj) {
+ _QCPGraphVtr.remove(i);
+ return;
+ }
+ }
+
+
+}
+
+
+
+}
diff --git a/src/ui/itemmanager.h b/src/ui/itemmanager.h
new file mode 100644
index 0000000..986bb64
--- /dev/null
+++ b/src/ui/itemmanager.h
@@ -0,0 +1,33 @@
+#ifndef ITEMMANAGER_H
+#define ITEMMANAGER_H
+
+#include "qcustomplot.h"
+
+namespace ItemManager {
+const QString OriginStr("origin");
+const QString ConfirmStr("confirm");
+const QString TemporaryStr("temporary");
+
+#if 0
+enum ItemAttribute{
+ Origin,
+ Last,
+ Temporary
+};
+#endif
+
+extern QVector _QCPItemTextVtr;
+extern QVector _QCPItemLineVtr;
+extern QVector _QCPGraphVtr;
+
+void addTemporaryQCPItemText(QCPItemText*);
+void addTemporaryQCPItemLine(QCPItemLine*);
+void addTemporaryQCPGraph(QCPGraph*);
+
+void removeItem(QObject* obj);
+
+void confirm();
+
+}
+
+#endif // ITEMMANAGER_H