2025-04-03T17:24:27

This commit is contained in:
yuntang 2025-04-03 17:24:29 +08:00
parent fc961c8e0b
commit 47a55ee938
12 changed files with 666 additions and 186 deletions

View File

@ -17,7 +17,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
data/filemanager.cpp \
data/peakpoint.cpp \
data/pointcalculate.cpp \
global.cpp \
logger/logger.cpp \
rightwidget.cpp \
@ -32,11 +32,12 @@ SOURCES += \
ui/draglinehandler.cpp \
ui/experimentsettingform.cpp \
ui/leftwidget.cpp \
ui/realtimedataform.cpp
ui/realtimedataform.cpp \
ui/specificheatcomparisonmethodform.cpp
HEADERS += \
data/filemanager.h \
data/peakpoint.h \
data/pointcalculate.h \
defines.h \
global.h \
logger/logger.h \
@ -52,12 +53,14 @@ HEADERS += \
ui/draglinehandler.h \
ui/experimentsettingform.h \
ui/leftwidget.h \
ui/realtimedataform.h
ui/realtimedataform.h \
ui/specificheatcomparisonmethodform.h
FORMS += \
mainwindow.ui \
ui/experimentsettingform.ui \
ui/realtimedataform.ui
ui/realtimedataform.ui \
ui/specificheatcomparisonmethodform.ui
INCLUDEPATH += serialport \
ui \

View File

@ -1,16 +1,20 @@
#include <QDebug>
#include "peakpoint.h"
#include "pointcalculate.h"
#include "logger.h"
QVector<FileManager::ExperimentData>PeakPoint:: _dataVtr;
QPointF PeakPoint::_peakPoint;
QPointF PeakPoint::_leftSelectedPoint,PeakPoint::_rightSelectedPoint;
QVector<FileManager::ExperimentData>PointCalculate:: _dataVtr;
QPointF PointCalculate::_peakPoint;
QPointF PointCalculate::_leftSelectedPoint,PointCalculate::_rightSelectedPoint;
void PeakPoint::setExperimentData(const QVector<FileManager::ExperimentData> &dataVtr)
void PointCalculate::setExperimentData(const QVector<FileManager::ExperimentData> &dataVtr)
{
_dataVtr = dataVtr;
if(_dataVtr.empty()) {
return;
}
FileManager::ExperimentData startPoint = _dataVtr.at(0);
FileManager::ExperimentData endPoint = _dataVtr.at(_dataVtr.size() - 1);
@ -18,7 +22,18 @@ void PeakPoint::setExperimentData(const QVector<FileManager::ExperimentData> &da
_rightSelectedPoint = QPointF(endPoint.sampleTemp,endPoint.dsc);
}
QPointF PeakPoint::findPeakPoint(){
std::vector<float> PointCalculate::movingAverage(const std::vector<float>& data, int windowSize) {
std::vector<float> smoothedData;
for (size_t i = 0; i < data.size(); ++i) {
if (i + windowSize <= data.size()) {
float sum = std::accumulate(data.begin() + i, data.begin() + i + windowSize, 0.0);
smoothedData.push_back(sum / windowSize);
}
}
return smoothedData;
}
QPointF PointCalculate::getPeakPoint(){
int n = _dataVtr.size();
if (n < 3) {
@ -59,8 +74,8 @@ QPointF PeakPoint::findPeakPoint(){
return uniquePeak;
}
QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointDetail(
const PeakPoint::MaxDiffPointDetailType type)
QPair<QPointF, QPointF> PointCalculate::calculateMaxDiffPointDetail(
const PointCalculate::MaxDiffPointDetailType type)
{
#if 1
float maxDiff = std::numeric_limits<float>::min();
@ -104,18 +119,18 @@ QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointDetail(
}
QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointLeft()
QPair<QPointF, QPointF> PointCalculate::calculateMaxDiffPointLeft()
{
return calculateMaxDiffPointDetail(MaxDiffPointDetailType::Left);
}
QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointRight()
QPair<QPointF, QPointF> PointCalculate::calculateMaxDiffPointRight()
{
return calculateMaxDiffPointDetail(MaxDiffPointDetailType::Right);
}
#if 0
QPointF PeakPoint::findClosestY(float targetX)
QPointF PointCalculate::findClosestY(float targetX)
{
float minDiff = std::numeric_limits<float>::max();
QPointF resultPointF;
@ -133,7 +148,7 @@ QPointF PeakPoint::findClosestY(float targetX)
#endif
#if 0
QPointF PeakPoint::findClosestPointByX(float x) {
QPointF PointCalculate::findClosestPointByX(float x) {
int left = 0;
int right = _dataVtr.size() - 1;
@ -161,14 +176,14 @@ QPointF PeakPoint::findClosestPointByX(float x) {
}
#endif
void PeakPoint::setRegionPointX(const float left, const float right)
void PointCalculate::setRegionPointX(const float left, const float right)
{
logde<<"select point param left,right:"<<left<<","<<right;
_leftSelectedPoint = findClosestPointByX(left);
_rightSelectedPoint = findClosestPointByX(right);
_leftSelectedPoint = getClosestPointByX(left);
_rightSelectedPoint = getClosestPointByX(right);
_peakPoint = findPeakPoint();
_peakPoint = getPeakPoint();
logde<<"peak point:"<<_peakPoint.x()<<","<<_peakPoint.y();
//根据峰谷重置选择点。
@ -178,7 +193,7 @@ void PeakPoint::setRegionPointX(const float left, const float right)
logde<<"select point right:"<<_rightSelectedPoint.x()<<","<<_rightSelectedPoint.y();
}
QVector<QPointF> PeakPoint::getPeakPointGroup()
QVector<QPointF> PointCalculate::getPeakPointGroup()
{
QVector<QPointF> pointVtr;
for(FileManager::ExperimentData& ed:_dataVtr) {
@ -190,19 +205,9 @@ QVector<QPointF> PeakPoint::getPeakPointGroup()
return pointVtr;
}
double PeakPoint::calculateArea() {
double PointCalculate::calculateArea() {
//getPoint group
QVector<QPointF> points = getPeakPointGroup();
#if 0
for(QPointF point:points){
qDebug()<<"x,y:"<<QString::number(point.x(),'f',3)<<","
<<QString::number(point.y(),'f',3);
}
#endif
#if 0
qDebug()<<QString::number(points.at(0).x(),'f',3)<<","<<
QString::number(points.at(points.size() - 1).x(),'f',3);
#endif
//calculate Area
float integral = 0.0;
@ -212,23 +217,6 @@ double PeakPoint::calculateArea() {
return integral; // 至少需要两个点才能计算积分
}
#if 0
for (size_t i = 1; i < n; ++i) {
float dx = points[i].x() - points[i - 1].x();
float avg_y = (points[i].y() + points[i - 1].y()) / 2.0;
#if 0
float step = dx * std::abs(avg_y);
qDebug()<<points[i].x()<<","<<points[i].y()<<"integral:"<<integral<<","<<step;
#endif
integral += dx * std::abs(avg_y);
}
#endif
#if 0
double k = (y2 - y1) / (x2 - x1);
double b = y1 - k * x1;
#endif
//find a line.
double k = (_leftSelectedPoint.y() - _rightSelectedPoint.y()) /
(_leftSelectedPoint.x() - _rightSelectedPoint.x());
@ -259,17 +247,17 @@ double PeakPoint::calculateArea() {
return integral;
}
QPair<QPointF, QPointF> PeakPoint::calculateStartAndEndPoint()
QPair<QPointF, QPointF> PointCalculate::calculateStartAndEndPoint()
{
QPair<QPointF,QPointF> leftMaxDiffPointPair = PeakPoint::calculateMaxDiffPointLeft();
QPair<QPointF,QPointF> rightMaxDiffPointPair = PeakPoint::calculateMaxDiffPointRight();
QPair<QPointF,QPointF> leftMaxDiffPointPair = PointCalculate::calculateMaxDiffPointLeft();
QPair<QPointF,QPointF> rightMaxDiffPointPair = PointCalculate::calculateMaxDiffPointRight();
#if 0
logde<<"b1:"<<leftMaxDiffPointPair.first.x()<<","<<leftMaxDiffPointPair.first.y();
logde<<"b2:"<<leftMaxDiffPointPair.second.x()<<","<<leftMaxDiffPointPair.second.y();
logde<<"b3:"<<rightMaxDiffPointPair.first.x()<<","<<rightMaxDiffPointPair.first.y();
logde<<"b4:"<<rightMaxDiffPointPair.second.x()<<","<<rightMaxDiffPointPair.second.y();
#endif
QPointF startPoint = calculateIntersection(_leftSelectedPoint,_rightSelectedPoint,
leftMaxDiffPointPair.first,
leftMaxDiffPointPair.second);
@ -280,7 +268,7 @@ QPair<QPointF, QPointF> PeakPoint::calculateStartAndEndPoint()
return qMakePair(startPoint,endPoint);
}
void PeakPoint::updateStartEndPoint()
void PointCalculate::updateStartEndPoint()
{
//需要在a1和a2之间查询是否有高于a1和a2之间的点若存在则重新给a1、a2赋值
@ -300,7 +288,7 @@ void PeakPoint::updateStartEndPoint()
}
}
}
QString PeakPoint::textFormatPeakPoint(const float enthalpyValue,
QString PointCalculate::textFormatPeakPoint(const float enthalpyValue,
const float peakValue,
const float startPoint,
const float endPoint)
@ -317,7 +305,7 @@ QString PeakPoint::textFormatPeakPoint(const float enthalpyValue,
}
// 计算两条直线的交点
QPointF PeakPoint::calculateIntersection(const QPointF p1,const QPointF p2,
QPointF PointCalculate::calculateIntersection(const QPointF p1,const QPointF p2,
const QPointF p3, const QPointF p4){
// 直线的一般式: A1x + B1y + C1 = 0 和 A2x + B2y + C2 = 0
float A1 = p2.y() - p1.y();
@ -340,10 +328,10 @@ QPointF PeakPoint::calculateIntersection(const QPointF p1,const QPointF p2,
}
}
QPointF PeakPoint::findClosestPointByX(const float targetX)
QPointF PointCalculate::getClosestPointByX(const float targetX)
{
#if 0
float minDiff = std::numeric_limits<float>::max();
QPointF resultPointF;
for(FileManager::ExperimentData &ed:_dataVtr){
float diff = std::abs(ed.sampleTemp - targetX);
@ -352,11 +340,37 @@ QPointF PeakPoint::findClosestPointByX(const float targetX)
resultPointF = QPointF(ed.sampleTemp,ed.dsc);
}
}
#endif
int left = 0;
int right = _dataVtr.size() - 1;
while (left < right) {
int mid = left + (right - left)/2;
const FileManager::ExperimentData& ed = _dataVtr.at(mid);
if(ed.sampleTemp > targetX){
right = mid;
}else{
left = mid + 1;
}
}
//
QPointF resultPointF(_dataVtr.at(left).sampleTemp,
_dataVtr.at(left).dsc);
if(left > 0 &&
std::abs(resultPointF.x() - targetX) >
std::abs(_dataVtr.at(left - 1).sampleTemp - targetX)){
//
resultPointF = QPointF(_dataVtr.at(left - 1).sampleTemp,
_dataVtr.at(left - 1).dsc);
}
return resultPointF;
}
QString PeakPoint::textFormatNumbericalLabel(const QPointF point)
QString PointCalculate::textFormatNumbericalLabel(const QPointF point)
{
return QString("数值:\n"
"%1℃,%2"
@ -364,8 +378,11 @@ QString PeakPoint::textFormatNumbericalLabel(const QPointF point)
.arg(QString::number(point.y(), 'f', 3));
}
QPair<QPointF, QPointF> PeakPoint::getStartAndEndPoint()
QPair<QPointF, QPointF> PointCalculate::getStartAndEndPoint()
{
if(_dataVtr.empty()){
return qMakePair(QPointF(), QPointF());
}
FileManager::ExperimentData startPoint = _dataVtr.at(0);
FileManager::ExperimentData endPoint = _dataVtr.at(_dataVtr.size() - 1);
@ -373,3 +390,27 @@ QPair<QPointF, QPointF> PeakPoint::getStartAndEndPoint()
QPointF(startPoint.sampleTemp,startPoint.dsc),
QPointF(endPoint.sampleTemp,endPoint.dsc));
}
QString PointCalculate::textFormatStartPoint(const QPointF point)
{
return QString("外推起始点:\n"
"%1℃"
).arg(QString::number(point.x(), 'f', 3));
}
QString PointCalculate::textFormatEndPoint(const QPointF point)
{
return QString("外推终止点:\n"
"%1℃"
).arg(QString::number(point.x(), 'f', 3));
}
QPair<float,float> PointCalculate::getCurveInflectionPointTangent()
{
}
QVector<QPointF> PointCalculate::getRegionPoints(const float, const float)
{
}

View File

@ -1,25 +1,32 @@
#ifndef PEAKPOINT_H
#define PEAKPOINT_H
#ifndef POINTCALCULATE_H
#define POINTCALCULATE_H
#include <QPointF>
#include "filemanager.h"
namespace PeakPoint{
namespace PointCalculate{
void setExperimentData(const QVector<FileManager::ExperimentData>&);
QPair<QPointF,QPointF> getStartAndEndPoint();
void setRegionPointX(const float,const float);
QPointF findClosestPointByX(const float);
QPointF findPeakPoint();
QPointF getClosestPointByX(const float);
QPointF getPeakPoint();
QString textFormatPeakPoint(const float enthalpyValue,
const float peakValue,
const float startPoint,
const float endPoint);
QString textFormatNumbericalLabel(const QPointF);
QString textFormatStartPoint(const QPointF);
QString textFormatEndPoint(const QPointF);
QPair<QPointF,QPointF> calculateStartAndEndPoint();
double calculateArea();
//​获取曲线拐点处的切线
QPair<float,float> getCurveInflectionPointTangent();
QVector<QPointF> getRegionPoints(const float,const float);
//private
void updateStartEndPoint();
QPair<QPointF,QPointF> calculateMaxDiffPointLeft();
@ -33,10 +40,11 @@ QPair<QPointF,QPointF> calculateMaxDiffPointDetail(const MaxDiffPointDetailType
QPointF calculateIntersection(const QPointF p1,const QPointF p2,
const QPointF p3, const QPointF p4);
QVector<QPointF> getPeakPointGroup();
std::vector<float> movingAverage(const std::vector<float>& data, int windowSize);
extern QVector<FileManager::ExperimentData> _dataVtr;
extern QPointF _peakPoint;
extern QPointF _leftSelectedPoint,_rightSelectedPoint;
}
#endif // PEAKPOINT_H
#endif // POINTCALCULATE_H

View File

@ -17,6 +17,7 @@ MainWindow::MainWindow(QWidget *parent)
_rightWidget(new QDockWidget(this))
,_analysisSettingWidget(new AnalysisSettingForm(this))
,_contextMenu(new QMenu(this))
,_specificHeatComparisonMethodForm(new SpecificHeatComparisonMethodForm(this))
{
ui->setupUi(this);
this->setToolTip(".....");
@ -37,6 +38,8 @@ MainWindow::MainWindow(QWidget *parent)
connections();
//
_expertmentSettingForm->setWindowFlags(_expertmentSettingForm->windowFlags()| Qt::Dialog);
_specificHeatComparisonMethodForm->setWindowFlags(_specificHeatComparisonMethodForm->windowFlags()| Qt::Dialog);
_realTimeDataForm->setWindowFlags(_realTimeDataForm->windowFlags()| Qt::Dialog);
// _realTimeDataForm->show();
@ -203,3 +206,59 @@ void MainWindow::on_actionClearAllData_triggered()
{
_centralWidget->clearAllData();
}
void MainWindow::on_actionGlassTransition_triggered()
{
_rightWidget->show();
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::GlassTransition);
}
void MainWindow::on_actionOIT_triggered()
{
}
void MainWindow::on_actionSpecificHeatCompMethod_triggered()
{
_specificHeatComparisonMethodForm->show();
}
void MainWindow::on_actionDegreeOfCrystallinity_triggered()
{
}
void MainWindow::on_actionInstrumentParameter_triggered()
{
}
void MainWindow::on_actionInitialMeltingPoint_triggered()
{
}
void MainWindow::on_actionFinalMeltingPoint_triggered()
{
}
void MainWindow::on_actionOITAutoAnalysisParam_triggered()
{
}
void MainWindow::on_actionOITAutoAnalysisMode_triggered()
{
}
void MainWindow::on_actionTimeAxisAnalysisPCTMode_triggered()
{
}
void MainWindow::on_actionDegreeOfCuring_triggered()
{
}

View File

@ -12,6 +12,7 @@
#include "dataparser.h"
#include "rightwidget.h"
#include "analysissettingform.h"
#include "specificheatcomparisonmethodform.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
@ -42,6 +43,28 @@ private slots:
void on_actionPeakSynthesisAnalysis_triggered();
void on_actionClearAllData_triggered();
void on_actionGlassTransition_triggered();
void on_actionOIT_triggered();
void on_actionSpecificHeatCompMethod_triggered();
void on_actionDegreeOfCrystallinity_triggered();
void on_actionInstrumentParameter_triggered();
void on_actionInitialMeltingPoint_triggered();
void on_actionFinalMeltingPoint_triggered();
void on_actionOITAutoAnalysisParam_triggered();
void on_actionOITAutoAnalysisMode_triggered();
void on_actionTimeAxisAnalysisPCTMode_triggered();
void on_actionDegreeOfCuring_triggered();
private:
void connections();
void setActionEnable(const bool);
@ -54,5 +77,6 @@ private:
RealTimeDataForm* _realTimeDataForm;
QMenu* _contextMenu;
AnalysisSettingForm* _analysisSettingWidget;
SpecificHeatComparisonMethodForm* _specificHeatComparisonMethodForm;
};
#endif // MAINWINDOW_H

View File

@ -45,9 +45,22 @@
<string>分析</string>
</property>
<addaction name="actionNumericalLabel"/>
<addaction name="separator"/>
<addaction name="actionStartPoint"/>
<addaction name="actionStopPoint"/>
<addaction name="actionPeakSynthesisAnalysis"/>
<addaction name="actionGlassTransition"/>
<addaction name="actionOIT"/>
<addaction name="actionSpecificHeatCompMethod"/>
<addaction name="actionDegreeOfCrystallinity"/>
<addaction name="separator"/>
<addaction name="actionInstrumentParameter"/>
<addaction name="actionInitialMeltingPoint"/>
<addaction name="actionFinalMeltingPoint"/>
<addaction name="actionOITAutoAnalysisParam"/>
<addaction name="actionOITAutoAnalysisMode"/>
<addaction name="actionTimeAxisAnalysisPCTMode"/>
<addaction name="actionDegreeOfCuring"/>
</widget>
<widget class="QMenu" name="menu_5">
<property name="title">
@ -179,6 +192,61 @@
<string>清除所有数据</string>
</property>
</action>
<action name="actionGlassTransition">
<property name="text">
<string>玻璃化转变</string>
</property>
</action>
<action name="actionOIT">
<property name="text">
<string>氧化诱导期</string>
</property>
</action>
<action name="actionSpecificHeatCompMethod">
<property name="text">
<string>比热比较法</string>
</property>
</action>
<action name="actionDegreeOfCrystallinity">
<property name="text">
<string>结晶度</string>
</property>
</action>
<action name="actionInstrumentParameter">
<property name="text">
<string>仪器系数</string>
</property>
</action>
<action name="actionInitialMeltingPoint">
<property name="text">
<string>初融点</string>
</property>
</action>
<action name="actionFinalMeltingPoint">
<property name="text">
<string>终融点</string>
</property>
</action>
<action name="actionOITAutoAnalysisParam">
<property name="text">
<string>OIT自动分析参数</string>
</property>
</action>
<action name="actionOITAutoAnalysisMode">
<property name="text">
<string>OIT自动分析模式</string>
</property>
</action>
<action name="actionTimeAxisAnalysisPCTMode">
<property name="text">
<string>时间轴分析峰综合温度模式</string>
</property>
</action>
<action name="actionDegreeOfCuring">
<property name="text">
<string>固化度</string>
</property>
</action>
</widget>
<resources>
<include location="images.qrc"/>

View File

@ -6,13 +6,13 @@
#include "centralwidget.h"
#include "filemanager.h"
#include "peakpoint.h"
#include "pointcalculate.h"
#include "logger.h"
CentralWidget::CentralWidget(QWidget *parent)
: QWidget(parent),
_customPlot(new QCustomPlot(this))
,_nanlysisMode(AnalysisMode::None)
,_analysisMode(AnalysisMode::None)
{
setMouseTracking(true);
@ -74,14 +74,7 @@ CentralWidget::~CentralWidget()
void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode)
{
#if 0
if(_nanlysisMode == mode){
return;
}else{
_nanlysisMode = mode;
}
#endif
_nanlysisMode = mode;
_analysisMode = mode;
switch (mode)
{
@ -89,6 +82,7 @@ void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode)
case AnalysisMode::StartPoint:
case AnalysisMode::StopPoint:
case AnalysisMode::PeakSynthesisAnalysis:
case AnalysisMode::GlassTransition:
setEventHandlerEnable(true);
break;
default:
@ -138,7 +132,9 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &fileName)
{
qDebug() << "slotRecvAnalysisFileName" << fileName;
// QVector<FileManager::ExperimentData> dataVtr;
//
clearData(ClearDataMode::All);
//
_dataVtr.clear();
FileManager::readExperimentFile(fileName, _dataVtr);
@ -146,15 +142,23 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &fileName)
{
return;
}
//
// _customPlot->xAxis->setRange(0, 500);
// _customPlot->yAxis->setRange(-20, 20);
PointCalculate::setExperimentData(_dataVtr);
QPair<QPointF,QPointF>startEndPointPair = PointCalculate::getStartAndEndPoint();
PeakPoint::setExperimentData(_dataVtr);
QPointF endPoint = startEndPointPair.second;
_customPlot->xAxis->setRange(0, endPoint.x() / 3 * 4);
QPointF peakPoint = PointCalculate::getPeakPoint();
float absY = std::abs(peakPoint.y());
_customPlot->yAxis->setRange(- absY * 2,absY *2);
// 设置坐标轴标签
_customPlot->yAxis->setLabel("DSC/mW");
_customPlot->xAxis->setLabel("Temp/℃");
// 设置坐标轴范围,以便我们可以看到全部数据
_customPlot->xAxis->setRange(0, 500);
_customPlot->yAxis->setRange(-20, 20);
QVector<double> xVtr, yVtr;
for (FileManager::ExperimentData &ed : _dataVtr)
@ -176,13 +180,32 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &fileName)
void CentralWidget::slotAnalysisSettingApply()
{
switch (_nanlysisMode) {
switch (_analysisMode) {
case AnalysisMode::NumericalLabel:
{
QPointF selectPoint = PeakPoint::findClosestPointByX(
QPointF selectPoint = PointCalculate::getClosestPointByX(
_line1->point1->coords().x());
drawText(selectPoint,PeakPoint::textFormatNumbericalLabel(selectPoint));
drawText(selectPoint,PointCalculate::textFormatNumbericalLabel(selectPoint));
break;
}
case AnalysisMode::StartPoint:
case AnalysisMode::StopPoint:{
double x1 = _line1->point1->coords().x();
double x2 = _line2->point1->coords().x();
PointCalculate::setRegionPointX(x1,x2);
QPair<QPointF, QPointF> startEndPointPair =
PointCalculate::calculateStartAndEndPoint();
if(_analysisMode == AnalysisMode::StartPoint){
drawText(startEndPointPair.first,
PointCalculate::textFormatStartPoint(startEndPointPair.first));
}else{
drawText(startEndPointPair.second,
PointCalculate::textFormatEndPoint(startEndPointPair.second));
}
break;
}
@ -193,24 +216,33 @@ void CentralWidget::slotAnalysisSettingApply()
fillGraph(x1,x2);
PeakPoint::setRegionPointX(x1,x2);
PointCalculate::setRegionPointX(x1,x2);
//enthalpy
double enthalpyValue = PeakPoint::calculateArea();
double enthalpyValue = PointCalculate::calculateArea();
//peak
QPointF peakPoint = PeakPoint::findPeakPoint();
// qDebug()<<"peak point:"<<point;
QPointF peakPoint = PointCalculate::getPeakPoint();
//start point and end point
QPair<QPointF, QPointF> startEndPointPair =
PeakPoint::calculateStartAndEndPoint();
PointCalculate::calculateStartAndEndPoint();
drawText(peakPoint,PeakPoint::textFormatPeakPoint(enthalpyValue,
logde<<"start,end:"<<startEndPointPair.first.x()<<","
<<startEndPointPair.second.x();
drawText(peakPoint,PointCalculate::textFormatPeakPoint(enthalpyValue,
peakPoint.x(),
startEndPointPair.first.x(),
startEndPointPair.second.x()));
//
break;
}
case AnalysisMode::GlassTransition:
{
glassTransitionHandle();
//
break;
}
default:
break;
}
@ -220,7 +252,9 @@ void CentralWidget::slotAnalysisSettingConfirm()
{
slotAnalysisSettingApply();
setAnalysisMode(CentralWidget::AnalysisMode::None);
_line1->setVisible(false);
_line2->setVisible(false);
emit sigRightDockWidgetHide();
}
@ -234,7 +268,9 @@ void CentralWidget::slotAnalysisSettingCancel()
{
clearData(ClearDataMode::Undo);
setAnalysisMode(CentralWidget::AnalysisMode::None);
_line1->setVisible(false);
_line2->setVisible(false);
emit sigRightDockWidgetHide();
}
@ -277,23 +313,66 @@ void CentralWidget::contextMenuEvent(QContextMenuEvent *event)
emit sigContextMenuShow(point);
}
void CentralWidget::glassTransitionHandle()
{
QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x());
QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x());
logde<<"point1:"<<point1.x()<<","<<point1.y();
logde<<"point2:"<<point2.x()<<","<<point2.y();
QCPItemStraightLine *line1 = new QCPItemStraightLine(_customPlot);
line1->point1->setCoords(point1.x() - 55,point1.y());
line1->point2->setCoords(point1.x() + 55,point1.y());
line1->setPen(QPen(Qt::darkGreen));
line1->setSelectable(false);
line1->setVisible(true);
QCPItemStraightLine *line2 = new QCPItemStraightLine(_customPlot);
line2->point1->setCoords(point2.x() - 55,point2.y());
line2->point2->setCoords(point2.x() + 55,point2.y());
line2->setPen(QPen(Qt::darkGreen));
line2->setSelectable(false);
line2->setVisible(true);
_customPlot->replot();
}
void CentralWidget::setEventHandlerEnable(const bool flag)
{
logde<<"setEventHandlerEnable..."<<flag;
// line visiable func
auto lineVisiableFunc = [&](QCPItemStraightLine* line){
line->setSelected(flag);
line->setVisible(flag);
};
// todo. 当竖线隐藏时,需要设置不可选择模式。
_eventHandler->setEnable(flag);
_line1->setVisible(flag);
if(AnalysisMode::NumericalLabel != _nanlysisMode){
_line2->setVisible(flag);
#if 1
// move line to suitable position.
double xMax = _customPlot->xAxis->range().upper; // X 轴的最大值
logde<<"xMax:"<<xMax;
_line1->point1->setCoords(xMax / 3,_line1->point1->coords().y());
_line1->point2->setCoords(xMax / 3,_line1->point2->coords().y());
_line2->point1->setCoords(xMax / 3 * 2,_line2->point1->coords().y());
_line2->point2->setCoords(xMax / 3 * 2,_line2->point2->coords().y());
#endif
lineVisiableFunc(_line1);
if(AnalysisMode::NumericalLabel != _analysisMode){
lineVisiableFunc(_line2);
}
//
_customPlot->replot();
}
void CentralWidget::drawText(const QPointF point, const QString text)
{
// double y = PeakPoint::findClosestY(x);
// 创建标注文字QCPItemText
QCPItemText *textLabel = new QCPItemText(_customPlot);
textLabel->setPositionAlignment(Qt::AlignBottom | Qt::AlignHCenter); // 对齐方式
@ -314,91 +393,15 @@ void CentralWidget::drawText(const QPointF point, const QString text)
// 重绘图表以显示文本标签和箭头
_customPlot->replot();
#if 0
// 创建标注文字QCPItemText
QCPItemText *textLabel = new QCPItemText(_customPlot);
textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); // 对齐方式
textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标
textLabel->position->setCoords(x,
_graph->data()->at(x)->value + 0.5); // 假设标注在 x=5 的点上方
textLabel->setText("标注文字");
textLabel->setFont(QFont("Arial", 10));
textLabel->setPen(QPen(Qt::black)); // 文字边框
textLabel->setBrush(Qt::white); // 文字背景
// 创建指向点的线段QCPItemLine
QCPItemLine *arrow = new QCPItemLine(_customPlot);
arrow->start->setParentAnchor(textLabel->bottom); // 线段起点绑定到标注文字底部
arrow->end->setCoords(x, _graph->data()->at(x)->value); // 线段终点绑定到数据点
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
arrow->setPen(QPen(Qt::red, 2));
#endif
#if 0
if (!_graph || !_customPlot) {
return;
}
// 创建标注文字QCPItemText
QCPItemText *textLabel = new QCPItemText(_customPlot);
textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); // 对齐方式
textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标
// 查找最接近 x 的数据点
auto it = _graph->data()->findBegin(x);
if (it != _graph->data()->end()) {
double y = it->value + 0.5;
textLabel->position->setCoords(x, y);
textLabel->setText(text);
textLabel->setFont(QFont("Arial", 10));
textLabel->setPen(QPen(Qt::black)); // 文字边框
textLabel->setBrush(Qt::white); // 文字背景
// 创建指向点的线段QCPItemLine
QCPItemLine *arrow = new QCPItemLine(_customPlot);
arrow->start->setParentAnchor(textLabel->bottom); // 线段起点绑定到标注文字底部
arrow->end->setCoords(x, it->value); // 线段终点绑定到数据点
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
arrow->setPen(QPen(Qt::red, 2));
}
#endif
}
#if 0
double CentralWidget::findClosestY(double targetX) {
// 获取曲线数据容器
QSharedPointer<QCPDataContainer<QCPGraphData>> dataContainer =
_graph->data();
// 初始化最小差值和对应的 y 值
double minDiff = std::numeric_limits<double>::max();
double closestY = 0.0;
// 遍历数据容器
for (int i = 0; i < dataContainer->size(); ++i) {
double currentX = dataContainer->at(i)->key;
double currentY = dataContainer->at(i)->value;
// 计算当前 x 与目标 x 的差值的绝对值
double diff = std::abs(currentX - targetX);
// 更新最小差值和对应的 y 值
if (diff < minDiff) {
minDiff = diff;
closestY = currentY;
}
}
return closestY;
}
#endif
void CentralWidget::fillGraph(const double x1, const double x2)
{
//todo.未寻找x1\x2之间最大值。
double y1 = PeakPoint::findClosestPointByX(x1).y();
double y2 = PeakPoint::findClosestPointByX(x2).y();
double y1 = PointCalculate::getClosestPointByX(x1).y();
double y2 = PointCalculate::getClosestPointByX(x2).y();
QVector<double> xVtr,yVtr;
xVtr.push_back(x1);

View File

@ -19,7 +19,8 @@ public:
NumericalLabel,
StartPoint,
StopPoint,
PeakSynthesisAnalysis
PeakSynthesisAnalysis,
GlassTransition
};
CentralWidget(QWidget *parent = nullptr);
~CentralWidget();
@ -45,6 +46,7 @@ protected:
void timerEvent(QTimerEvent* event);
void contextMenuEvent(QContextMenuEvent *event);
private:
void glassTransitionHandle();
void setEventHandlerEnable(const bool);
void drawText(const QPointF,const QString);
void fillGraph(const double x1,const double x2);
@ -54,12 +56,13 @@ private:
};
void clearData(const ClearDataMode);
private:
AnalysisMode _nanlysisMode;
AnalysisMode _analysisMode;
QCustomPlot *_customPlot;
QCPGraph* _graph;
DragLineHandler* _eventHandler;
QCPItemStraightLine *_line1,*_line2;
QVector<FileManager::ExperimentData> _dataVtr;
QVector<QCPItemStraightLine*> _lineVtr;
};
#endif // CENTRALWIDGET_H

View File

@ -16,7 +16,7 @@ DragLineHandler::~DragLineHandler()
bool DragLineHandler::eventFilter(QObject *obj, QEvent *event)
{
if(!_enableFlag){
// qDebug()<<"_enableFlag false.";
// qDebug()<<"_enableFlag false.";
#if 0
if(mPlot){
mPlot->setCursor(Qt::ArrowCursor);
@ -29,25 +29,22 @@ bool DragLineHandler::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
{
// qDebug()<<"mouse move...";
// qDebug()<<"mouse move...";
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
QPoint mousePos = mouseEvent->pos();
// qDebug()<<"x:"<<mousePos.x();
// qDebug()<<"x:"<<mousePos.x();
bool nearLine1 = isNearLine(_line1, mousePos);
bool nearLine2 = isNearLine(_line2, mousePos);
if (nearLine1 || nearLine2)
if ((nearLine1 && _line1->visible()) ||
(nearLine2 && _line2->visible()))
{
_plot->setCursor(Qt::SplitHCursor);
// qDebug()<<"mIconLabel visiable.";
}
else
{
// qDebug()<<"mIconLabel not visiable.";
_plot->setCursor(Qt::ArrowCursor);
}
@ -67,7 +64,7 @@ bool DragLineHandler::eventFilter(QObject *obj, QEvent *event)
}
else if (event->type() == QEvent::MouseButtonPress)
{
// qDebug()<<"mouse press...";
// qDebug()<<"mouse press...";
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton)
@ -125,7 +122,7 @@ void DragLineHandler::updateSelectedRegion()
int index1 = findClosestIndex(xData, x1);
int index2 = findClosestIndex(xData, x2);
// qDebug() << "Selected region: [" << xData[index1] << ", " << xData[index2] << "]";
// qDebug() << "Selected region: [" << xData[index1] << ", " << xData[index2] << "]";
}
int DragLineHandler::findClosestIndex(const QVector<double> &data, double target)

View File

@ -0,0 +1,24 @@
#include "specificheatcomparisonmethodform.h"
#include "ui_specificheatcomparisonmethodform.h"
SpecificHeatComparisonMethodForm::SpecificHeatComparisonMethodForm(QWidget *parent) :
QWidget(parent),
ui(new Ui::SpecificHeatComparisonMethodForm)
{
ui->setupUi(this);
}
SpecificHeatComparisonMethodForm::~SpecificHeatComparisonMethodForm()
{
delete ui;
}
void SpecificHeatComparisonMethodForm::on_pushButtonCalculate_clicked()
{
}
void SpecificHeatComparisonMethodForm::on_pushButtonQuit_clicked()
{
hide();
}

View File

@ -0,0 +1,27 @@
#ifndef SPECIFICHEATCOMPARISONMETHODFORM_H
#define SPECIFICHEATCOMPARISONMETHODFORM_H
#include <QWidget>
namespace Ui {
class SpecificHeatComparisonMethodForm;
}
class SpecificHeatComparisonMethodForm : public QWidget
{
Q_OBJECT
public:
explicit SpecificHeatComparisonMethodForm(QWidget *parent = nullptr);
~SpecificHeatComparisonMethodForm();
private slots:
void on_pushButtonCalculate_clicked();
void on_pushButtonQuit_clicked();
private:
Ui::SpecificHeatComparisonMethodForm *ui;
};
#endif // SPECIFICHEATCOMPARISONMETHODFORM_H

View File

@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SpecificHeatComparisonMethodForm</class>
<widget class="QWidget" name="SpecificHeatComparisonMethodForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<height>556</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>19</x>
<y>19</y>
<width>281</width>
<height>471</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>参数</string>
</property>
<widget class="QWidget" name="formLayoutWidget">
<property name="geometry">
<rect>
<x>9</x>
<y>30</y>
<width>261</width>
<height>81</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="LabelTemperature">
<property name="text">
<string>温度(℃)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="LineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="LabelCorrectionCoefficient">
<property name="text">
<string>校正系数</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="LineEdit_2"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>数据文件</string>
</property>
<widget class="QWidget" name="formLayoutWidget_2">
<property name="geometry">
<rect>
<x>9</x>
<y>29</y>
<width>261</width>
<height>81</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="LabelBaseLine">
<property name="text">
<string>基线</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="LineEdit_3"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="LabelGuideSample">
<property name="text">
<string>标样</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="LineEdit_4"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="LabelSample">
<property name="text">
<string>样品</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="LineEdit_5"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>相关参数</string>
</property>
<widget class="QWidget" name="formLayoutWidget_3">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>261</width>
<height>81</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="LabelSampleWeight">
<property name="text">
<string>样品质量</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="LineEditSampleWeight"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="Label">
<property name="text">
<string>标样质量</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="LineEditGuideSampleWeight"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="jGLabel">
<property name="text">
<string>标样比热(J/(g*℃))</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="LineEditStandardSampleSpecificHeat"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>计算结果</string>
</property>
<widget class="QWidget" name="formLayoutWidget_4">
<property name="geometry">
<rect>
<x>9</x>
<y>29</y>
<width>261</width>
<height>41</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="Label_2">
<property name="text">
<string>样品比热(J/(g*℃))</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="LineEditSampleSpecificHeat"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pushButtonCalculate">
<property name="geometry">
<rect>
<x>100</x>
<y>520</y>
<width>80</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>计算</string>
</property>
</widget>
<widget class="QPushButton" name="pushButtonQuit">
<property name="geometry">
<rect>
<x>200</x>
<y>520</y>
<width>80</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>退出</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>