2025-05-22T17:31:37

This commit is contained in:
yuntang 2025-05-22 17:31:38 +08:00
parent 4f15bc595f
commit 14a507ad45
13 changed files with 350 additions and 41 deletions

Binary file not shown.

View File

@ -9,7 +9,7 @@ CONFIG+=precompile_header
PRECOMPILED_HEADER=stable.h
#
VERSION = 0.9.9
VERSION = 1.0.0
# 设置目标文件名,包含版本号
TARGET = AnalysisTool_$${VERSION}

View File

@ -429,20 +429,6 @@ QString PointCalculate::textFormatNumbericalLabel(const QPointF point)
.arg(QString::number(point.y(), 'f', 3));
}
QPair<QPointF, QPointF> PointCalculate::getStartAndEndPoint()
{
if(_dataVtr.empty()){
return qMakePair(QPointF(), QPointF());
}
Global::ExperimentData startPoint = _dataVtr.at(0);
Global::ExperimentData endPoint = _dataVtr.at(_dataVtr.size() - 1);
return qMakePair<QPointF,QPointF>(
QPointF(startPoint.sampleTemp,startPoint.dsc),
QPointF(endPoint.sampleTemp,endPoint.dsc));
}
QString PointCalculate::textFormatStartPoint(const QPointF point)
{
return QString("外推起始点:\n"
@ -623,6 +609,45 @@ QMap<double, PointCalculate::Line> PointCalculate::calculateTangentLine(
return tangentLines;
}
QPair<float, float> PointCalculate::getTheMaximumAndMinimumValuesOfTime(
const double min,const double max)
{
float sampleTempMax = std::numeric_limits<float>::min();
float sampleTempMin = std::numeric_limits<float>::max();
float runTimeMax = std::numeric_limits<float>::min();
float runTimeMin = std::numeric_limits<float>::max();
for(Global::ExperimentData& ed:_dataVtr){
if(ed.sampleTemp > sampleTempMax){
sampleTempMax = ed.sampleTemp;
}
if(ed.sampleTemp < sampleTempMin){
sampleTempMin = ed.sampleTemp;
}
if(ed.runTime > runTimeMax){
runTimeMax = ed.runTime;
}
if(ed.runTime < runTimeMin){
runTimeMin = ed.runTime;
}
}
//
double tempDiff = max - min;
double dataTempDiff = sampleTempMax - sampleTempMin;
double dataTimeDiff = runTimeMax - runTimeMin;
// timeDiff / dataTimeDiff = tempDiff / dataTempDiff;
double timeDiff = tempDiff * dataTimeDiff / dataTempDiff;
return qMakePair<float,float>(0.0,timeDiff);
}
QVector<QPointF> PointCalculate::getPointVtrInXRange(const float x1, const float x2)
{
QVector<QPointF> targetVtr;
@ -666,4 +691,62 @@ double PointCalculate::obtainTimeValueBasedOnTemperatureValue(const double sampl
return targetValue;
}
QPair<float, float> PointCalculate::getMinAndMaxOfAxis(const float min, const float max)
{
double diff = max - min;
double center = diff / 2;
return qMakePair<float,float>(min - diff * 0.2,
max + diff * 0.2);
}
QPair<float, float> PointCalculate::getMinAndMaxOfSampleTemp()
{
float sampleTempMax = std::numeric_limits<float>::min();
float sampleTempMin = std::numeric_limits<float>::max();
for(Global::ExperimentData& ed:_dataVtr){
if(ed.sampleTemp > sampleTempMax){
sampleTempMax = ed.sampleTemp;
}
if(ed.sampleTemp < sampleTempMin){
sampleTempMin = ed.sampleTemp;
}
}
return qMakePair<float,float>(sampleTempMin,sampleTempMax);
}
QPair<float, float> PointCalculate::getMinAndMaxOfRunTime()
{
float runTimeMax = std::numeric_limits<float>::min();
float runTimeMin = std::numeric_limits<float>::max();
for(Global::ExperimentData& ed:_dataVtr){
if(ed.runTime > runTimeMax){
runTimeMax = ed.runTime;
}
if(ed.runTime < runTimeMin){
runTimeMin = ed.runTime;
}
}
return qMakePair<float,float>(runTimeMin,runTimeMax);
}
QPair<float, float> PointCalculate::getMinAndMaxOfDSC()
{
float dscMax = std::numeric_limits<float>::min();
float dscMin = std::numeric_limits<float>::max();
for(Global::ExperimentData& ed:_dataVtr){
if(ed.dsc > dscMax){
dscMax = ed.dsc;
}
if(ed.dsc < dscMin){
dscMin = ed.dsc;
}
}
return qMakePair<float,float>(dscMin,dscMax);
}

View File

@ -9,7 +9,13 @@
namespace PointCalculate{
void setAnalysisData(const QVector<Global::ExperimentData>&);
QPair<QPointF,QPointF> getStartAndEndPoint();
//QPair<QPointF,QPointF> getStartAndEndPoint();
QPair<float,float> getMinAndMaxOfSampleTemp();
QPair<float,float> getMinAndMaxOfRunTime();
QPair<float,float> getMinAndMaxOfDSC();
QPair<float,float> getMinAndMaxOfAxis(const float min,const float max);
QVector<Global::ExperimentData> getDataInXRange(const float, const float);
QVector<QPointF> getPointVtrInXRange(const float, const float);
@ -22,6 +28,10 @@ QPointF getClosestPointByY(const double left,const double right,const double val
QPointF getPeakPoint();
QPair<float, float> getMaxMinValue();
// According to the value of plot x axis witch of temperature value.
QPair<float, float> getTheMaximumAndMinimumValuesOfTime(
const double min,const double max);
QPair<QPointF,QPointF> calculateStartAndEndPoint();
float calculateArea();
double obtainTimeValueBasedOnTemperatureValue(const double sampleTemp);

View File

@ -274,7 +274,8 @@ void XlsxHandler::writeFile(const QString filePath)
//
xlsx.write(phaseSizeRow , 1, ConPhaseSize);
xlsx.write(phaseSizeRow , 2, phaseCount);
//
writeAnalysisOperationDetail(&xlsx,row);
//
logde<<"before xlsx save as...";
if (!xlsx.saveAs(filePath)) {
@ -303,6 +304,9 @@ void XlsxHandler::writeAnalysisOperation(const QString filePath)
int row = index + 1;
writeAnalysisOperationDetail(xlsx,row);
#if 0
QVector<AnalysisOperationRecorder::AnalysisOperation>& aoVtr =
AnalysisOperationRecorder::_analysisOperationVtr;
@ -357,6 +361,7 @@ void XlsxHandler::writeAnalysisOperation(const QString filePath)
xlsx->write(row , 3, ao.x2);
row++;
}
#endif
// save
#if 1
@ -419,6 +424,8 @@ void XlsxHandler::readAnalysisOperation(
ao.filePath = cfd.fileName;
logde<<"cfd fileName:"<<cfd.fileName.toStdString();
QString modeStr = sheet->cellAt(startLineIndex, 1)->value().toString();
if(modeStr == AnaOpRecorder::NumericalLabelStr){
@ -448,3 +455,64 @@ void XlsxHandler::readAnalysisOperation(
logde<<"x1:"<<ao.x1<<",x2:"<<ao.x2;
}
}
void XlsxHandler::writeAnalysisOperationDetail(QXlsx::Document *xlsx, const int row)
{
int localRow = row;
Q_UNUSED(row)
QVector<AnalysisOperationRecorder::AnalysisOperation>& aoVtr =
AnalysisOperationRecorder::_analysisOperationVtr;
xlsx->write(localRow , 1, ConAnalysisOperationCount);
xlsx->write(localRow , 2, aoVtr.size());
localRow++;
for (AnaOpRecorderOperation& ao:aoVtr){
QString analysisOpName;
switch(ao.mode){
case AnalysisMode::NumericalLabel:
{
analysisOpName = AnalysisOperationRecorder::NumericalLabelStr;
break;
}
case AnalysisMode::StartPoint:
{
analysisOpName = AnalysisOperationRecorder::StartPointStr;
break;
}
case AnalysisMode::StopPoint:
{
analysisOpName = AnalysisOperationRecorder::StopPointStr;
break;
}
case AnalysisMode::PeakSynthesisAnalysis:
{
analysisOpName = AnalysisOperationRecorder::PeakSynthesisAnalysisStr;
break;
}
case AnalysisMode::GlassTransition:
{
analysisOpName = AnalysisOperationRecorder::GlassTransitionStr;
break;
}
case AnalysisMode::OnsetTemperaturePoint:
{
analysisOpName = AnalysisOperationRecorder::OnsetTemperaturePointStr;
break;
}
case AnalysisMode::EndsetTemperaturePoint:
{
analysisOpName = AnalysisOperationRecorder::EndsetTemperaturePointStr;
break;
}
default:break;
}
xlsx->write(localRow , 1, analysisOpName);
xlsx->write(localRow , 2, ao.x1);
xlsx->write(localRow , 3, ao.x2);
localRow++;
}
}

View File

@ -26,6 +26,7 @@ namespace XlsxHandler {
void writeFile(const QString filePath);
void writeAnalysisOperation(const QString filePath);
void writeAnalysisOperationDetail(QXlsx::Document*doc,const int row);
extern QString _currentFilePath;

View File

@ -4,7 +4,7 @@
#include "global.h"
namespace Global {
Mode _mode;
Mode _mode = Mode::Analysis;
QVector<CurveFileData> _curveFileDataVtr;

View File

@ -33,6 +33,7 @@ const double DefaultParamter = 8.177;
//
enum Mode{
None,
Analysis,
ConnectedToDev,
DeliveredData,
@ -100,7 +101,7 @@ extern ExperimentInfo _experimentInfo;
extern QVector<CurveExperimentData> _curveExperimentDataVtr;
extern CurveExperimentData* _currentCurveExperimentDataPtr;
// Call this function at the right time.
// Call clear function at the right time.
void clearExperimentData();
// Instrument coefficient.
@ -114,6 +115,7 @@ extern bool _displayTimeValue;
QString converDoubleToStr(const double);
void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[]);
double findNegativeStartPoint(double m, double b, double start, double end);
};
#endif // GLOBAL_H

View File

@ -249,7 +249,9 @@ bool MainWindow::saveFile(const QString fileName,const Global::Mode mode)
}
QString folder;
if(mode == Global::Mode::Analysis){
if(mode == Global::Mode::None){
folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
}else if(mode == Global::Mode::Analysis){
folder = Global::AnalysisStateFolder;
}else if(mode == Global::Mode::Experiment){
folder = Global::SampleDataFloder;
@ -461,7 +463,6 @@ void MainWindow::on_actionAbout_triggered()
_aboutForm->show();
}
void MainWindow::on_actionEnthalpyCorrectionEdit_triggered()
{
_enthalpyDataCorrectionForm->show();
@ -474,7 +475,7 @@ void MainWindow::on_actionEnthalpyCorrectionSelection_triggered()
void MainWindow::on_actionPrintPreview_triggered()
{
// _printPreviewForm->show();
// _printPreviewForm->show();
_printPreviewForm->setPixmap(_centralWidget->getPixMap());
_printPreviewForm->_customPrintPreviewDialog->showMaximized();
@ -507,3 +508,9 @@ void MainWindow::on_actionSaveData_triggered()
saveFile(Global::_experimentInfo.sampleName,Global::_mode);
_leftWidget->reloadFileName();
}
void MainWindow::on_actionSaveas_triggered()
{
saveFile(Global::_experimentInfo.sampleName,Global::Mode::None);
_leftWidget->reloadFileName();
}

View File

@ -94,6 +94,8 @@ private slots:
void on_actionSaveData_triggered();
void on_actionSaveas_triggered();
private:
void connections();
void setActionEnable(const bool);

View File

@ -29,6 +29,7 @@
</property>
<addaction name="actionNew"/>
<addaction name="actionSaveData"/>
<addaction name="actionSaveas"/>
<addaction name="actionPrintPreview"/>
</widget>
<widget class="QMenu" name="menu_2">
@ -329,6 +330,11 @@
<string>坐标轴设置</string>
</property>
</action>
<action name="actionSaveas">
<property name="text">
<string>另存为</string>
</property>
</action>
</widget>
<resources>
<include location="images.qrc"/>

View File

@ -88,8 +88,9 @@ CentralWidget::CentralWidget(QWidget *parent)
#endif
// 设置坐标轴标签
_customPlot->xAxis->setLabel("Temp/℃");
_customPlot->yAxis->setLabel("DSC/mW");
_customPlot->xAxis->setLabel(AxisTemperature);
_customPlot->yAxis->setLabel(AxisDSC);
// 设置坐标轴范围,以便我们可以看到全部数据
_customPlot->xAxis->setRange(0,100);
_customPlot->yAxis->setRange(0,20);
@ -103,6 +104,7 @@ CentralWidget::~CentralWidget()
void CentralWidget::switchAxisMode()
{
if(Global::_mode != Global::Mode::Analysis){
return;
}
@ -110,10 +112,7 @@ void CentralWidget::switchAxisMode()
if(_axisMode == AxisMode::SingleY){
_axisMode = AxisMode::DoubleY;
_customPlot->yAxis2->setVisible(true);
_customPlot->yAxis2->setLabel(XlsxHandler::ConPhaseHeaderTemp);
_customPlot->yAxis->setLabel(XlsxHandler::ConPhaseHeaderTime);
clearData(ClearDataMode::All);
#if 0
_customPlot->yAxis2->setVisible(true);
@ -150,10 +149,17 @@ void CentralWidget::switchAxisMode()
}
#endif
}else{
logde<<"_axisMode == AxisMode::DoubleY ...";
_axisMode = AxisMode::SingleY;
clearData(ClearDataMode::All);
#if 0
_customPlot->yAxis2->setVisible(false);
_customPlot->xAxis->setLabel(AxisTemperature);
for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) {
QCPAbstractPlottable* plottable = _customPlot->plottable(i);
if (auto curve = dynamic_cast<QCPCurve*>(plottable)) {
@ -162,9 +168,11 @@ void CentralWidget::switchAxisMode()
}
}
}
#endif
}
_customPlot->replot();
uiLoadXlsxFileData();
}
void CentralWidget::setAnalysisMode(const AnalysisMode mode)
@ -275,7 +283,13 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &filePath)
QMessageBox::warning((QWidget*)this->parent(), "warnning", "File parse error.");
return;
}
// Add data to global parameter.
Global::_curveFileDataVtr.push_back(cfd);
//
uiLoadXlsxFileData();
#if 0
for(int i = 0;i < cfd.phaseTotalVtr.size();i++){
Global::PhaseTotalInfo& pti = cfd.phaseTotalVtr[i];
@ -313,9 +327,6 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &filePath)
pti.curve = _currentCurve;
}
// Add data to global parameter.
Global::_curveFileDataVtr.push_back(cfd);
// Add analysis operation data.
if(cfd.analysisOperationVtr.size() > 0){
for(AnaOpRecorder::AnalysisOperation& ao
@ -326,6 +337,7 @@ void CentralWidget::slotRecvAnalysisFileName(const QString &filePath)
// Refresh ui.
_customPlot->rescaleAxes();
_customPlot->replot();
#endif
}
void CentralWidget::slotAnalysisSettingApply()
@ -336,12 +348,21 @@ void CentralWidget::slotAnalysisSettingApply()
return;
}
QVector<Global::ExperimentData> dataVtr;
for(Global::CurveFileData& cfd:Global::_curveFileDataVtr){
for(Global::PhaseTotalInfo& pti:cfd.phaseTotalVtr){
if(pti.curve == _currentCurve){
PointCalculate::setAnalysisData(pti.dataVtr);
break;
if(Global::_curveFileDataVtr.empty()){
// Load experiment data.
for(Global::CurveExperimentData& ced:Global::_curveExperimentDataVtr){
if(ced.curve == _currentCurve){
PointCalculate::setAnalysisData(ced.dataVtr);
}
}
}else{
// Load xlsx file data.
for(Global::CurveFileData& cfd:Global::_curveFileDataVtr){
for(Global::PhaseTotalInfo& pti:cfd.phaseTotalVtr){
if(pti.curve == _currentCurve){
PointCalculate::setAnalysisData(pti.dataVtr);
break;
}
}
}
}
@ -525,6 +546,90 @@ void CentralWidget::slotSelectionChangedByUser()
}
}
void CentralWidget::uiLoadXlsxFileData()
{
// Set axis.
_customPlot->yAxis->setVisible(true);
_customPlot->yAxis->setLabel(AxisDSC);
if(_axisMode == AxisMode::SingleY){
_customPlot->xAxis->setLabel(AxisTemperature);
_customPlot->yAxis2->setVisible(false);
}else{
_customPlot->xAxis->setLabel(AxisTime);
_customPlot->yAxis2->setVisible(true);
_customPlot->yAxis2->setLabel(AxisTemperature);
}
#if 1
// Load xlsx file data.
for(Global::CurveFileData& cfd:Global::_curveFileDataVtr){
for(int i = 0;i < cfd.phaseTotalVtr.size();i++){
Global::PhaseTotalInfo& pti = cfd.phaseTotalVtr[i];
PointCalculate::setAnalysisData(pti.dataVtr);
// Load data.
QVector<Global::ExperimentData> dataVtr;
QVector<double> tVtr,xVtr, yVtr;
int index = 0;
for (Global::ExperimentData &ed : pti.dataVtr)
{
tVtr.push_back(index++);
if(_axisMode == AxisMode::SingleY){
xVtr.push_back(ed.sampleTemp);
}else{
xVtr.push_back(ed.runTime);
}
yVtr.push_back(ed.dsc);
}
_currentCurve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis);
_currentCurve->setData(tVtr, xVtr, yVtr);
_currentCurve->setSelectable(QCP::stWhole); // 设置曲线可选
_currentCurve->setLineStyle(QCPCurve::lsLine); // 线性连接
_currentCurve->setObjectName(cfd.fileName);
// Set axis range.
QPair<float, float> minMaxXAxisPair;
if(_axisMode == AxisMode::SingleY){
// Axis x is temperature value.
minMaxXAxisPair = PointCalculate::getMinAndMaxOfSampleTemp();
}else{
// Axis x is time value.
minMaxXAxisPair = PointCalculate::getMinAndMaxOfRunTime();
}
QPair<float, float>newXAxisPair = PointCalculate::getMinAndMaxOfAxis(
minMaxXAxisPair.first,minMaxXAxisPair.second);
_customPlot->xAxis->setRange(newXAxisPair.first, newXAxisPair.second);
QPair<float, float> minMaxYAxisPair = PointCalculate::getMinAndMaxOfDSC();
QPair<float, float>newYAxisPair = PointCalculate::getMinAndMaxOfAxis(
minMaxYAxisPair.first,minMaxYAxisPair.second);
_customPlot->yAxis->setRange(newYAxisPair.first ,
newYAxisPair.second);
//
pti.curve = _currentCurve;
}
// Add analysis operation data.
if(cfd.analysisOperationVtr.size() > 0){
for(AnaOpRecorder::AnalysisOperation& ao
:cfd.analysisOperationVtr){
loadAnalysisData(ao.mode,ao.x1,ao.x2,cfd.fileName);
}
}
}
// Refresh ui.
_customPlot->replot();
#endif
}
#if 0
void CentralWidget::contextMenuEvent(QContextMenuEvent *event)
{
@ -922,13 +1027,27 @@ void CentralWidget::fillGraph(const double x1, const double x2,const QString obj
void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
{
switch (mode) {
case ClearDataMode::All:
break;
case ClearDataMode::JustUi:
break;
case ClearDataMode::Undo:
break;
default:break;
}
if(mode == ClearDataMode::All){
}else if(mode == ClearDataMode::All){
//
_analysisFilePathVtr.clear();
// Clear data.
logde<<"clearExperimentData...";
Global::clearExperimentData();
Global::_curveFileDataVtr.clear();
// Set lines visiable false.
_line1->setVisible(false);
_line2->setVisible(false);
@ -1018,7 +1137,11 @@ void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
void CentralWidget::deleteCurve(const QString objectName)
{
_analysisFilePathVtr.removeOne(objectName);
for (int i = _analysisFilePathVtr.size() - 1; i >= 0; --i) {
if (_analysisFilePathVtr[i].startsWith(objectName)) {
_analysisFilePathVtr.removeAt(i); // 从后往前删除避免索引错乱
}
}
ItemManager::removeItemsByObjectName(objectName);
@ -1133,7 +1256,7 @@ void CentralWidget::loadAnalysisData(
}else{
}
}else{
// logde<<"current curve nullptr.";
// logde<<"current curve nullptr.";
}
}
}

View File

@ -74,6 +74,12 @@ protected:
private slots:
void slotSelectionChangedByUser();
private:
const QString AxisTime = "Time/min";
const QString AxisTemperature = "Temperature/℃";
const QString AxisDSC = "DSC/mW";
void uiLoadXlsxFileData();
void glassTransitionHandle(const double x1,const double x2,const QString objectName);
void quadraticFit(const QVector<QPointF>& points, double& a, double& b, double& c);
double derivativeAt(const double a, const double b, const double x);
@ -89,7 +95,8 @@ private:
enum ClearDataMode{
All,
Undo
Undo,
JustUi
};
void clearData(const ClearDataMode);
void deleteCurve(const QString);