diff --git a/experiment_data/analysis_state/22-new.xlsx b/experiment_data/analysis_state/22-new.xlsx new file mode 100644 index 0000000..4feb39a Binary files /dev/null and b/experiment_data/analysis_state/22-new.xlsx differ diff --git a/src/AnalysisTool.pro b/src/AnalysisTool.pro index 02b5263..a24145c 100644 --- a/src/AnalysisTool.pro +++ b/src/AnalysisTool.pro @@ -9,7 +9,7 @@ CONFIG+=precompile_header PRECOMPILED_HEADER=stable.h # -VERSION = 0.9.9 +VERSION = 1.0.0 # 设置目标文件名,包含版本号 TARGET = AnalysisTool_$${VERSION} diff --git a/src/data/pointcalculate.cpp b/src/data/pointcalculate.cpp index 9e65835..f817221 100644 --- a/src/data/pointcalculate.cpp +++ b/src/data/pointcalculate.cpp @@ -429,20 +429,6 @@ QString PointCalculate::textFormatNumbericalLabel(const QPointF point) .arg(QString::number(point.y(), 'f', 3)); } -QPair 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(startPoint.sampleTemp,startPoint.dsc), - QPointF(endPoint.sampleTemp,endPoint.dsc)); -} - QString PointCalculate::textFormatStartPoint(const QPointF point) { return QString("外推起始点:\n" @@ -623,6 +609,45 @@ QMap PointCalculate::calculateTangentLine( return tangentLines; } + +QPair PointCalculate::getTheMaximumAndMinimumValuesOfTime( + const double min,const double max) +{ + + float sampleTempMax = std::numeric_limits::min(); + float sampleTempMin = std::numeric_limits::max(); + + float runTimeMax = std::numeric_limits::min(); + float runTimeMin = std::numeric_limits::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(0.0,timeDiff); +} + QVector PointCalculate::getPointVtrInXRange(const float x1, const float x2) { QVector targetVtr; @@ -666,4 +691,62 @@ double PointCalculate::obtainTimeValueBasedOnTemperatureValue(const double sampl return targetValue; } +QPair PointCalculate::getMinAndMaxOfAxis(const float min, const float max) +{ + double diff = max - min; + double center = diff / 2; + return qMakePair(min - diff * 0.2, + max + diff * 0.2); +} +QPair PointCalculate::getMinAndMaxOfSampleTemp() +{ + float sampleTempMax = std::numeric_limits::min(); + float sampleTempMin = std::numeric_limits::max(); + + for(Global::ExperimentData& ed:_dataVtr){ + if(ed.sampleTemp > sampleTempMax){ + sampleTempMax = ed.sampleTemp; + } + if(ed.sampleTemp < sampleTempMin){ + sampleTempMin = ed.sampleTemp; + } + } + + return qMakePair(sampleTempMin,sampleTempMax); +} + +QPair PointCalculate::getMinAndMaxOfRunTime() +{ + float runTimeMax = std::numeric_limits::min(); + float runTimeMin = std::numeric_limits::max(); + + for(Global::ExperimentData& ed:_dataVtr){ + if(ed.runTime > runTimeMax){ + runTimeMax = ed.runTime; + } + if(ed.runTime < runTimeMin){ + runTimeMin = ed.runTime; + } + } + + return qMakePair(runTimeMin,runTimeMax); +} + +QPair PointCalculate::getMinAndMaxOfDSC() +{ + float dscMax = std::numeric_limits::min(); + float dscMin = std::numeric_limits::max(); + + for(Global::ExperimentData& ed:_dataVtr){ + if(ed.dsc > dscMax){ + dscMax = ed.dsc; + } + if(ed.dsc < dscMin){ + dscMin = ed.dsc; + } + } + + return qMakePair(dscMin,dscMax); +} + diff --git a/src/data/pointcalculate.h b/src/data/pointcalculate.h index 5af3be7..afb1608 100644 --- a/src/data/pointcalculate.h +++ b/src/data/pointcalculate.h @@ -9,7 +9,13 @@ namespace PointCalculate{ void setAnalysisData(const QVector&); -QPair getStartAndEndPoint(); +//QPair getStartAndEndPoint(); +QPair getMinAndMaxOfSampleTemp(); +QPair getMinAndMaxOfRunTime(); +QPair getMinAndMaxOfDSC(); + +QPair getMinAndMaxOfAxis(const float min,const float max); + QVector getDataInXRange(const float, const float); QVector getPointVtrInXRange(const float, const float); @@ -22,6 +28,10 @@ QPointF getClosestPointByY(const double left,const double right,const double val QPointF getPeakPoint(); QPair getMaxMinValue(); +// According to the value of plot x axis witch of temperature value. +QPair getTheMaximumAndMinimumValuesOfTime( + const double min,const double max); + QPair calculateStartAndEndPoint(); float calculateArea(); double obtainTimeValueBasedOnTemperatureValue(const double sampleTemp); diff --git a/src/data/xlsxhandler.cpp b/src/data/xlsxhandler.cpp index 9210afc..621d0ac 100644 --- a/src/data/xlsxhandler.cpp +++ b/src/data/xlsxhandler.cpp @@ -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& 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:"<cellAt(startLineIndex, 1)->value().toString(); if(modeStr == AnaOpRecorder::NumericalLabelStr){ @@ -448,3 +455,64 @@ void XlsxHandler::readAnalysisOperation( logde<<"x1:"<& 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++; + } +} diff --git a/src/data/xlsxhandler.h b/src/data/xlsxhandler.h index 62f655c..212efdd 100644 --- a/src/data/xlsxhandler.h +++ b/src/data/xlsxhandler.h @@ -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; diff --git a/src/global.cpp b/src/global.cpp index 9ceefbf..3c52e52 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -4,7 +4,7 @@ #include "global.h" namespace Global { -Mode _mode; +Mode _mode = Mode::Analysis; QVector _curveFileDataVtr; diff --git a/src/global.h b/src/global.h index 3ae66b4..59c6fcc 100644 --- a/src/global.h +++ b/src/global.h @@ -33,6 +33,7 @@ const double DefaultParamter = 8.177; // enum Mode{ + None, Analysis, ConnectedToDev, DeliveredData, @@ -100,7 +101,7 @@ extern ExperimentInfo _experimentInfo; extern QVector _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 diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9d747c8..a10a11a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -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(); +} diff --git a/src/mainwindow.h b/src/mainwindow.h index 144f2ec..07f1707 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -94,6 +94,8 @@ private slots: void on_actionSaveData_triggered(); + void on_actionSaveas_triggered(); + private: void connections(); void setActionEnable(const bool); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 3e61ece..e960ae1 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -29,6 +29,7 @@ + @@ -329,6 +330,11 @@ 坐标轴设置 + + + 另存为 + + diff --git a/src/ui/centralwidget.cpp b/src/ui/centralwidget.cpp index c1a6bb7..0a2eeb9 100644 --- a/src/ui/centralwidget.cpp +++ b/src/ui/centralwidget.cpp @@ -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(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 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 dataVtr; + QVector 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 minMaxXAxisPair; + if(_axisMode == AxisMode::SingleY){ + // Axis x is temperature value. + minMaxXAxisPair = PointCalculate::getMinAndMaxOfSampleTemp(); + }else{ + // Axis x is time value. + minMaxXAxisPair = PointCalculate::getMinAndMaxOfRunTime(); + } + QPairnewXAxisPair = PointCalculate::getMinAndMaxOfAxis( + minMaxXAxisPair.first,minMaxXAxisPair.second); + _customPlot->xAxis->setRange(newXAxisPair.first, newXAxisPair.second); + + QPair minMaxYAxisPair = PointCalculate::getMinAndMaxOfDSC(); + QPairnewYAxisPair = 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."; } } } diff --git a/src/ui/centralwidget.h b/src/ui/centralwidget.h index aae9e36..2e91dd0 100644 --- a/src/ui/centralwidget.h +++ b/src/ui/centralwidget.h @@ -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& 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);