DSCAnalysisTool/src/data/xlsxhandler.cpp

451 lines
13 KiB
C++
Raw Normal View History

2025-04-12 13:02:37 +00:00
#include "xlsxhandler.h"
#include "logger.h"
2025-05-12 09:29:59 +00:00
#include "analysisoperationrecorder.h"
2025-05-13 09:33:40 +00:00
#include "global.h"
namespace AnaOpRecorder = AnalysisOperationRecorder;
using AnaOpRecorderOperation = AnalysisOperationRecorder::AnalysisOperation;
2025-05-16 09:28:45 +00:00
using AnalysisMode = AnalysisOperationRecorder::AnalysisMode;
2025-05-14 09:30:52 +00:00
2025-05-13 09:33:40 +00:00
QString XlsxHandler::_currentFilePath;
2025-04-12 13:02:37 +00:00
void XlsxHandler::test()
{
2025-04-15 08:03:00 +00:00
#if 0
2025-04-12 13:02:37 +00:00
QString sourceFilePath = QDir::currentPath() + "/sample.xlsx";
2025-04-13 10:10:29 +00:00
qDebug() << "fileName:" << sourceFilePath;
2025-04-12 13:02:37 +00:00
readFile(sourceFilePath);
2025-04-15 08:03:00 +00:00
#endif
2025-05-13 09:33:40 +00:00
2025-04-15 08:03:00 +00:00
QString sourceFilePath = QDir::currentPath() + "/sample-save.xlsx";
writeFile(sourceFilePath);
2025-04-12 13:02:37 +00:00
}
2025-05-13 09:33:40 +00:00
2025-05-16 09:01:40 +00:00
int XlsxHandler::readFile(const QString filePath, Global::CurveFileData &cfd)
2025-04-12 13:02:37 +00:00
{
2025-05-16 09:01:40 +00:00
if(!QFile::exists(filePath))
2025-04-13 10:10:29 +00:00
{
2025-05-16 09:01:40 +00:00
qDebug() << "xlsx file not existed:" << filePath;
2025-04-15 08:03:00 +00:00
return 1;
2025-04-12 13:02:37 +00:00
}
2025-05-16 09:01:40 +00:00
QFileInfo fileInfo(filePath);
2025-04-12 13:02:37 +00:00
2025-04-15 08:03:00 +00:00
// 获取文件的后缀名并转换为小写,方便比较
QString fileSuffix = fileInfo.suffix().toLower();
2025-04-12 13:02:37 +00:00
2025-04-15 08:03:00 +00:00
// 判断后缀名是否为 "xlsx"
if (fileSuffix != "xlsx") {
std::cout << "该文件的后缀不是 xlsx" << std::endl;
return 2;
}
2025-05-16 09:01:40 +00:00
_currentFilePath = filePath;
2025-05-16 09:28:45 +00:00
cfd.fileName = fileInfo.fileName();
2025-05-13 09:33:40 +00:00
2025-05-16 09:01:40 +00:00
QXlsx::Document xlsx(filePath);
2025-04-12 13:02:37 +00:00
QXlsx::Worksheet *workSheet = xlsx.currentWorksheet();
2025-04-13 10:10:29 +00:00
if(!workSheet)
{
2025-04-15 08:03:00 +00:00
logde << "current sheet is empty.";
return 3;
2025-04-12 13:02:37 +00:00
}
2025-04-15 08:03:00 +00:00
//
int index = 2;
Global::ExperimentInfo& ei = cfd.ei;
2025-04-13 10:10:29 +00:00
ei.sampleName = workSheet->cellAt(index++, 2)->value().toString();
2025-04-12 13:02:37 +00:00
ei.sampleWeight = workSheet->cellAt(index++, 2)->value().toString();
2025-04-24 08:41:20 +00:00
logde<<"xlsx sample weight:"<<ei.sampleWeight.toStdString();
2025-04-14 09:11:01 +00:00
index++; // skip crucible weight.
2025-04-12 13:02:37 +00:00
ei.date = workSheet->cellAt(index++, 2)->value().toString();
2025-04-14 09:11:01 +00:00
ei.experimentor = workSheet->cellAt(index++, 2)->value().toString();
index++; // skip measure type.
2025-04-12 13:02:37 +00:00
ei.phaseSize = workSheet->cellAt(index++, 2)->value().toInt();
2025-04-15 08:03:00 +00:00
QVector<Global::PhaseTotalInfo>& phaseTotalVtr = cfd.phaseTotalVtr;
2025-05-13 09:33:40 +00:00
int dataIndex = 9;
2025-04-13 10:10:29 +00:00
for(int i = 0; i < ei.phaseSize; i++)
{
Global::PhaseTotalInfo phaseTotal;
phaseTotal.phaseIndex = i + 1;
2025-05-13 09:33:40 +00:00
readPhaseData(workSheet, dataIndex, phaseTotal);
2025-04-13 10:10:29 +00:00
phaseTotalVtr.push_back(phaseTotal);
2025-05-20 09:30:02 +00:00
// print
logde<<"index:"<<i<<",phase cut off temp:"<<phaseTotal.phase.cutoff_temp;
2025-04-12 13:02:37 +00:00
}
2025-05-13 09:33:40 +00:00
2025-05-20 09:30:02 +00:00
logde<<"index:"<<cfd.phaseTotalVtr.first().phaseIndex
<<",phase cut off temp:"<<cfd.phaseTotalVtr.first().phase.cutoff_temp;
2025-05-13 09:33:40 +00:00
logde<<"dataIndex:"<<dataIndex;
2025-05-16 09:01:40 +00:00
readAnalysisOperation(workSheet,dataIndex,cfd);
2025-05-13 09:33:40 +00:00
2025-04-15 08:03:00 +00:00
return 0;
2025-04-13 10:10:29 +00:00
}
2025-04-12 13:02:37 +00:00
2025-04-13 10:10:29 +00:00
void XlsxHandler::readPhaseData(QXlsx::Worksheet *workSheet, int &startLineIndex,
Global::PhaseTotalInfo &phaseTotal)
{
2025-04-14 09:11:01 +00:00
// skip.# Time/min Temp/℃ Voltage/mW
2025-04-13 10:10:29 +00:00
startLineIndex++;
2025-04-14 09:11:01 +00:00
// skip.第一段
2025-04-13 10:10:29 +00:00
startLineIndex++;
2025-04-23 09:25:38 +00:00
logde<<"startLineIndex:"<<startLineIndex;
2025-05-20 09:30:02 +00:00
phaseTotal.phase.onoff = 1;
2025-04-14 09:11:01 +00:00
phaseTotal.phase.cutoff_temp = workSheet->cellAt(startLineIndex++, 2)->value().toDouble();
phaseTotal.phase.temp_flow = workSheet->cellAt(startLineIndex++, 2)->value().toDouble();
2025-04-13 10:10:29 +00:00
phaseTotal.phase.constant_temp_time_min = (uint16_t)(workSheet->cellAt(startLineIndex++, 2)->value().toInt());
phaseTotal.phase.gas = static_cast<GasType>(workSheet->cellAt(startLineIndex++, 2)->value().toInt());
int dataSize = workSheet->cellAt(startLineIndex++, 2)->value().toInt();
2025-05-13 09:33:40 +00:00
logde<<"data size:"<<dataSize;
2025-04-13 10:10:29 +00:00
for(int i = 0; i < dataSize; i++)
{
Global::ExperimentData data;
2025-04-14 09:11:01 +00:00
data.runTime = workSheet->cellAt(startLineIndex, 2)->value().toDouble();
data.sampleTemp = workSheet->cellAt(startLineIndex, 3)->value().toDouble();
data.dsc = workSheet->cellAt(startLineIndex, 4)->value().toDouble();
2025-04-13 10:10:29 +00:00
phaseTotal.dataVtr.push_back(data);
2025-04-14 09:11:01 +00:00
startLineIndex++;
2025-04-13 10:10:29 +00:00
}
2025-04-12 13:02:37 +00:00
}
2025-04-15 08:03:00 +00:00
void XlsxHandler::writeFile(const QString filePath)
2025-04-12 13:02:37 +00:00
{
2025-05-15 09:31:03 +00:00
if(Global::_curveExperimentDataVtr.empty()){
logde<<"_curveExperimentDataVtr empty...";
return;
}
2025-04-14 09:11:01 +00:00
Global::ExperimentInfo& ei = Global::_experimentInfo;
2025-04-13 10:10:29 +00:00
QXlsx::Document xlsx;
xlsx.addSheet("Sheet1"); // 添加一个新的工作表
2025-04-14 09:11:01 +00:00
2025-04-15 08:03:00 +00:00
// Write experiment info.
int row = 1;
2025-04-14 09:11:01 +00:00
xlsx.write(row++ , 1, ConFileDataInfo);
xlsx.write(row , 1, ConSampleName);
2025-04-23 09:25:38 +00:00
QString sampleName = ei.sampleName;
if(sampleName.isEmpty()){
sampleName = "sample";
}
xlsx.write(row , 2, sampleName);
2025-04-14 09:11:01 +00:00
row++;
xlsx.write(row , 1, ConSampleWeight);
2025-04-23 09:25:38 +00:00
QString sampleWeight = ei.sampleWeight;
if(sampleWeight.isEmpty()){
sampleWeight = "1";
}
xlsx.write(row , 2, sampleWeight);
2025-04-14 09:11:01 +00:00
xlsx.write(row , 3, ConUnitMg);
row++;
xlsx.write(row , 1, ConCrucibleWeight);
xlsx.write(row , 2, 0);
xlsx.write(row , 3, ConUnitMg);
row++;
xlsx.write(row , 1, Conexperimenter);
2025-04-23 09:25:38 +00:00
QString experimentor = ei.experimentor;
if(experimentor.isEmpty()){
experimentor = "experimentor";
}
xlsx.write(row , 2, experimentor);
2025-04-14 09:11:01 +00:00
row++;
xlsx.write(row , 1, ConDate);
2025-04-23 09:25:38 +00:00
QString date = ei.date;
if(date.isEmpty()){
date = "20250101";
}
xlsx.write(row , 2, date);
2025-04-14 09:11:01 +00:00
row++;
xlsx.write(row , 1, ConMeasureType);
xlsx.write(row , 2, "样品");
row++;
2025-04-23 09:25:38 +00:00
int phaseSizeRow = row;
int phaseCount = 0;
2025-04-14 09:11:01 +00:00
xlsx.write(row , 1, ConPhaseSize);
xlsx.write(row , 2, ei.phaseVtr.size());
row++;
2025-04-15 08:03:00 +00:00
// Write phase data.
2025-04-14 09:11:01 +00:00
int dataSizeRow = 0;
2025-04-23 09:25:38 +00:00
logde<<"phase vtr size:"<<ei.phaseVtr.size();
2025-04-14 09:11:01 +00:00
for(int i = 0; i < ei.phaseVtr.size();i++){
2025-04-23 09:25:38 +00:00
logde<<"phase index:"<<i;
2025-04-14 09:11:01 +00:00
const Phase& phase = ei.phaseVtr.at(i);
2025-04-23 09:25:38 +00:00
if(phase.onoff == 0){
logde<<"onoff == 0.";
continue;
}
phaseCount++;
2025-04-14 09:11:01 +00:00
xlsx.write(row , 1, ConPhaseProfix);
xlsx.write(row , 2, ConPhaseHeaderTime);
xlsx.write(row , 3, ConPhaseHeaderTemp);
xlsx.write(row , 4, ConPhaseHeaderVoltage);
2025-04-30 02:59:08 +00:00
xlsx.write(row , 5, ConPhaseHeaderTime);
2025-04-14 09:11:01 +00:00
row++;
xlsx.write(row , 1, ConPhaseIndex);
xlsx.write(row , 2, i + 1);
row++;
2025-05-21 08:36:47 +00:00
2025-04-14 09:11:01 +00:00
// phase info
xlsx.write(row , 1, ConPhaseCutoffTemp);
xlsx.write(row , 2, phase.cutoff_temp);
xlsx.write(row , 3, ConUnitDegreeCentigrade);
row++;
xlsx.write(row , 1, ConPhaseHeatingRate);
xlsx.write(row , 2, phase.temp_flow);
xlsx.write(row , 3, ConUnitDegreeCentigradePerMin);
row++;
xlsx.write(row , 1, ConPhaseConstantTempTime);
xlsx.write(row , 2, phase.constant_temp_time_min);
xlsx.write(row , 3, ConUnitMin);
row++;
xlsx.write(row , 1, ConPhaseAtmosphere);
switch(phase.gas){
case GasType::NC:
xlsx.write(row , 2, "NC");
break;
case GasType::N2:
xlsx.write(row , 2, "N2");
break;
case GasType::O2:
xlsx.write(row , 2, "O2");
break;
default:break;
}
row++;
// phase data.
2025-05-16 09:01:40 +00:00
// logde<<"Global::_curveExperimentDataVtr size:"
// <<Global::_curveExperimentDataVtr.size();
2025-04-15 08:03:00 +00:00
const QVector<Global::ExperimentData>& edVtr =
Global::_curveExperimentDataVtr.at(i).dataVtr;
// phase data size.
2025-04-14 09:11:01 +00:00
dataSizeRow = row;
xlsx.write(row , 1, ConPhaseDataSize);
2025-04-15 08:03:00 +00:00
xlsx.write(row , 2, edVtr.size());
2025-04-14 09:11:01 +00:00
row++;
2025-05-16 09:01:40 +00:00
// logde<<"edVtr size:"<<edVtr.size();
2025-04-23 07:33:39 +00:00
2025-04-15 08:03:00 +00:00
for(int index = 0;index < edVtr.size();index++){
2025-05-16 09:01:40 +00:00
// logde<<"index :"<<index;
2025-04-15 08:03:00 +00:00
const Global::ExperimentData & ed = edVtr.at(index);
xlsx.write(row , 1, index);
xlsx.write(row , 2, ed.runTime);
2025-04-23 09:25:38 +00:00
xlsx.write(row , 3, ed.sampleTemp);
xlsx.write(row , 4, ed.dsc);
xlsx.write(row , 5, ed.constantTempTime);
row++;
2025-04-15 08:03:00 +00:00
}
2025-04-14 09:11:01 +00:00
}
2025-04-23 09:25:38 +00:00
//
xlsx.write(phaseSizeRow , 1, ConPhaseSize);
xlsx.write(phaseSizeRow , 2, phaseCount);
2025-04-14 09:11:01 +00:00
2025-04-23 09:25:38 +00:00
//
logde<<"before xlsx save as...";
2025-04-15 08:03:00 +00:00
if (!xlsx.saveAs(filePath)) {
logde<<"Save xlsx failed.";
return ;
}
2025-04-13 10:10:29 +00:00
2025-04-12 13:02:37 +00:00
}
2025-04-15 08:03:00 +00:00
2025-05-13 09:33:40 +00:00
void XlsxHandler::writeAnalysisOperation(const QString filePath)
{
QXlsx::Document* xlsx = openXlsxFile(_currentFilePath);
if(!xlsx){
logde<<"xlsx is nullptr." ;
return;
}
QXlsx::Worksheet *sheet = xlsx->currentWorksheet();
if(!sheet)
{
logde << "current sheet is empty.";
return;
}
int index = sheet->dimension().lastRow();
logde<<"lastRow:"<<index;
int row = index + 1;
2025-05-16 09:01:40 +00:00
2025-05-13 09:33:40 +00:00
QVector<AnalysisOperationRecorder::AnalysisOperation>& aoVtr =
2025-05-16 09:28:45 +00:00
AnalysisOperationRecorder::_analysisOperationVtr;
2025-05-13 09:33:40 +00:00
xlsx->write(row , 1, ConAnalysisOperationCount);
xlsx->write(row , 2, aoVtr.size());
row++;
for (AnaOpRecorderOperation& ao:aoVtr){
QString analysisOpName;
switch(ao.mode){
2025-05-14 09:30:52 +00:00
case AnalysisMode::NumericalLabel:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::NumericalLabelStr;
break;
}
2025-05-16 09:28:45 +00:00
case AnalysisMode::StartPoint:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::StartPointStr;
break;
}
2025-05-16 09:28:45 +00:00
case AnalysisMode::StopPoint:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::StopPointStr;
break;
}
2025-05-16 09:28:45 +00:00
case AnalysisMode::PeakSynthesisAnalysis:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::PeakSynthesisAnalysisStr;
break;
}
2025-05-16 09:28:45 +00:00
case AnalysisMode::GlassTransition:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::GlassTransitionStr;
break;
}
2025-05-16 09:28:45 +00:00
case AnalysisMode::OnsetTemperaturePoint:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::OnsetTemperaturePointStr;
break;
}
2025-05-16 09:28:45 +00:00
case AnalysisMode::EndsetTemperaturePoint:
2025-05-13 09:33:40 +00:00
{
analysisOpName = AnalysisOperationRecorder::EndsetTemperaturePointStr;
break;
}
default:break;
}
xlsx->write(row , 1, analysisOpName);
xlsx->write(row , 2, ao.x1);
xlsx->write(row , 3, ao.x2);
row++;
}
2025-05-12 09:29:59 +00:00
2025-05-13 09:33:40 +00:00
// save
#if 1
if (!xlsx->saveAs(filePath)) {
logde<<"Save xlsx failed.";
delete xlsx;
return ;
}
#endif
//
delete xlsx;
logde<<"Save xlsx succ.";
}
QXlsx::Document* XlsxHandler::openXlsxFile(const QString& sourceFilePath) {
// 检查文件是否存在
if (!QFile::exists(sourceFilePath)) {
qDebug() << "xlsx file not existed:" << sourceFilePath;
return nullptr;
}
QFileInfo fileInfo(sourceFilePath);
// 获取文件的后缀名并转换为小写,方便比较
QString fileSuffix = fileInfo.suffix().toLower();
// 判断后缀名是否为 "xlsx"
if (fileSuffix != "xlsx") {
std::cout << "该文件的后缀不是 xlsx" << std::endl;
return nullptr;
}
QXlsx::Document* xlsx = new QXlsx::Document(sourceFilePath);
QXlsx::Worksheet* workSheet = xlsx->currentWorksheet();
if (!workSheet) {
qDebug() << "current sheet is empty.";
delete xlsx;
return nullptr;
}
return xlsx;
}
2025-05-16 09:01:40 +00:00
void XlsxHandler::readAnalysisOperation(
QXlsx::Worksheet *sheet, int &startLineIndex,Global::CurveFileData& cfd)
2025-05-12 09:29:59 +00:00
{
2025-05-14 09:30:52 +00:00
QXlsx::Cell *cell = sheet->cellAt(startLineIndex, 2);
if (!cell) {
logde << "Cell does not exist.";
return;
}
2025-05-13 09:33:40 +00:00
int size = sheet->cellAt(startLineIndex++, 2)->value().toInt();
logde<<"ana op size:"<<size;
for(int i = 0;i < size; i++){
AnaOpRecorderOperation ao;
2025-05-16 09:01:40 +00:00
2025-05-19 05:58:34 +00:00
ao.filePath = cfd.fileName;
2025-05-16 09:01:40 +00:00
2025-05-13 09:33:40 +00:00
QString modeStr = sheet->cellAt(startLineIndex, 1)->value().toString();
if(modeStr == AnaOpRecorder::NumericalLabelStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::NumericalLabel;
2025-05-13 09:33:40 +00:00
}else if(modeStr == AnaOpRecorder::StartPointStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::StartPoint;
2025-05-13 09:33:40 +00:00
}else if(modeStr == AnaOpRecorder::StopPointStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::StopPoint;
2025-05-13 09:33:40 +00:00
}else if(modeStr == AnaOpRecorder::PeakSynthesisAnalysisStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::PeakSynthesisAnalysis;
2025-05-13 09:33:40 +00:00
}else if(modeStr == AnaOpRecorder::GlassTransitionStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::GlassTransition;
2025-05-13 09:33:40 +00:00
}else if(modeStr == AnaOpRecorder::OnsetTemperaturePointStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::OnsetTemperaturePoint;
2025-05-13 09:33:40 +00:00
}else if(modeStr == AnaOpRecorder::EndsetTemperaturePointStr){
2025-05-16 09:28:45 +00:00
ao.mode = AnalysisMode::EndsetTemperaturePoint;
2025-05-13 09:33:40 +00:00
}
ao.x1 = sheet->cellAt(startLineIndex, 2)->value().toDouble();
ao.x2 = sheet->cellAt(startLineIndex, 3)->value().toDouble();
2025-05-12 09:29:59 +00:00
2025-05-16 09:01:40 +00:00
cfd.analysisOperationVtr.push_back(ao);
2025-05-13 09:33:40 +00:00
startLineIndex++;
logde<<" ao mode:"<<modeStr.toStdString();
logde<<"x1:"<<ao.x1<<",x2:"<<ao.x2;
}
2025-05-12 09:29:59 +00:00
}