add,计划采集2:

添加计划任务的数据结构,并实现读写数据结构
This commit is contained in:
tangchao0503
2026-06-02 16:33:17 +08:00
parent 6111634eff
commit 3521a7f225
6 changed files with 418 additions and 0 deletions

View File

@ -162,6 +162,7 @@
</ClCompile>
<ClCompile Include="TabManager.cpp" />
<ClCompile Include="TimedDataCollection.cpp" />
<ClCompile Include="TimedDataCollectionDataStructures.cpp" />
<ClCompile Include="TwoMotorControl.cpp" />
<ClCompile Include="utility_tc.cpp" />
<ClCompile Include="View3D.cpp" />
@ -253,6 +254,7 @@
<QtMoc Include="rgbCameraWindow.h" />
<QtMoc Include="SingleLensReflexCameraWindow.h" />
<QtMoc Include="TimedDataCollection.h" />
<ClInclude Include="TimedDataCollectionDataStructures.h" />
<ClInclude Include="utility_tc.h" />
<QtMoc Include="aboutWindow.h" />
<ClInclude Include="hppaConfigFile.h" />

View File

@ -235,6 +235,9 @@
<ClCompile Include="TimedDataCollection.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TimedDataCollectionDataStructures.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<QtMoc Include="fileOperation.h">
@ -437,6 +440,9 @@
<ClInclude Include="MotorWindowBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TimedDataCollectionDataStructures.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<QtUic Include="FocusDialog.ui">

View File

@ -1,4 +1,6 @@
#include "TimedDataCollection.h"
#include <QDateTime>
#include <QDebug>
TimedDataCollection::TimedDataCollection(QWidget* parent)
: QDialog(parent)
@ -9,8 +11,110 @@ TimedDataCollection::TimedDataCollection(QWidget* parent)
ui.treeWidget->setAcceptDrops(true); // 接受拖放
ui.treeWidget->setDropIndicatorShown(true); // 显示插入位置指示线
ui.treeWidget->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动
//writeRead();
readTimedTaskFromFile("D:/0tmp/3Dtest/task.json");
connect(ui.run_btn, SIGNAL(clicked()), this, SLOT(run()));
connect(ui.run_btn, &QPushButton::clicked, this, &TimedDataCollection::run);
}
TimedDataCollection::~TimedDataCollection()
{
}
void TimedDataCollection::run()
{
}
void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
{
// 从文件读取
if (TimedDataCollectionDataStructuresReaderWriter::loadTasksFromFile(filePath, m_loadedTasks)) {
qDebug() << "Tasks loaded successfully, count:" << m_loadedTasks.size();
for (const auto& t : m_loadedTasks) {
qDebug() << " Task ID:" << t.id << "SubTasks:" << t.subTasks.size();
}
}
else {
qDebug() << "Failed to load tasks from:" << filePath;
}
int a = 1;
}
void TimedDataCollection::writeRead()
{
// 创建2个定时任务测试
QVector<TimedTask> tasks;
for (int i = 0; i < 2; ++i) {
TimedTask task;
task.id = i + 1;
task.scheduledTime = QDateTime::currentDateTime().addDays(i + 1);
task.savePath = QString("D:/0tmp/data");
task.status = TaskStatus::Waiting;
// 创建4种子任务
QVector<SubTaskType> types = {
SubTaskType::HyperSpectual400_1000nm,
SubTaskType::HyperSpectual1000_1700nm,
SubTaskType::SingleLensReflex,
SubTaskType::DepthCamera
};
for (int j = 0; j < types.size(); ++j) {
SubTask subTask;
subTask.type = types[j];
subTask.startTime = task.scheduledTime.addSecs(j * 3600);
subTask.endTime = subTask.startTime.addSecs(1800);
subTask.durationSeconds = 1800;
subTask.estimatedDurationSeconds = 1800;
subTask.pathLineFilePath = QString("D:/0tmp/3Dtest/pathLine/%1.RecordLine3").arg(j);
subTask.status = TaskStatus::Waiting;
// 根据类型设置特有属性
if (subTask.type == SubTaskType::HyperSpectual400_1000nm ||
subTask.type == SubTaskType::HyperSpectual1000_1700nm) {
subTask.frameRate = 30.0;
subTask.exposureTime = 1;
}
if (subTask.type == SubTaskType::HyperSpectual1000_1700nm) {
subTask.defaultRenderBand = 1200;
}
if (subTask.type == SubTaskType::SingleLensReflex ||
subTask.type == SubTaskType::DepthCamera) {
subTask.captureIntervalSeconds = 5;
}
task.subTasks.append(subTask);
}
tasks.append(task);
}
// 保存到文件
QString filePath = "D:/0tmp/3Dtest/task.json";
if (TimedDataCollectionDataStructuresReaderWriter::saveTasksToFile(filePath, tasks)) {
qDebug() << "Tasks saved to:" << filePath;
}
else {
qDebug() << "Failed to save tasks to:" << filePath;
}
// 从文件读取
QVector<TimedTask> loadedTasks;
if (TimedDataCollectionDataStructuresReaderWriter::loadTasksFromFile(filePath, loadedTasks)) {
qDebug() << "Tasks loaded successfully, count:" << loadedTasks.size();
for (const auto& t : loadedTasks) {
qDebug() << " Task ID:" << t.id << "SubTasks:" << t.subTasks.size();
}
}
else {
qDebug() << "Failed to load tasks from:" << filePath;
}
int a = 1;
}

View File

@ -6,6 +6,7 @@
#include <QNetworkAccessManager>
#include "ui_TimedDataCollection_ui.h"
#include "TimedDataCollectionDataStructures.h"
class TimedDataCollection : public QDialog
{
@ -15,10 +16,15 @@ public:
TimedDataCollection(QWidget* parent = nullptr);
~TimedDataCollection();
void readTimedTaskFromFile(const QString& filePath);
public Q_SLOTS:
void run();
private:
Ui::TimedDataCollection_ui ui;
void writeRead();
QVector<TimedTask> m_loadedTasks;
};

View File

@ -0,0 +1,196 @@
#include "TimedDataCollectionDataStructures.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QTextStream>
#include <QDebug>
// ==================== 公共接口实现 ====================
bool TimedDataCollectionDataStructuresReaderWriter::saveTasksToFile(const QString& filePath, const QVector<TimedTask>& tasks)
{
QJsonObject root;
root["version"] = "1.0";
root["taskCount"] = tasks.size();
QJsonArray tasksArray;
for (const auto& task : tasks) {
tasksArray.append(timedTaskToJson(task));
}
root["tasks"] = tasksArray;
QJsonDocument doc(root);
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Failed to open file for writing:" << filePath;
return false;
}
QTextStream out(&file);
//out.setEncoding(QStringConverter::Utf8);
out << doc.toJson(QJsonDocument::Indented);
file.close();
return true;
}
bool TimedDataCollectionDataStructuresReaderWriter::loadTasksFromFile(const QString& filePath, QVector<TimedTask>& tasks)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Failed to open file for reading:" << filePath;
return false;
}
QByteArray jsonData = file.readAll();
file.close();
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "JSON parse error:" << parseError.errorString();
return false;
}
if (!doc.isObject()) {
qWarning() << "Invalid JSON root object";
return false;
}
QJsonObject root = doc.object();
QJsonArray tasksArray = root["tasks"].toArray();
tasks.clear();
tasks.reserve(tasksArray.size());
for (const auto& taskValue : tasksArray) {
if (!taskValue.isObject()) continue;
TimedTask task;
if (jsonToTimedTask(taskValue.toObject(), task)) {
tasks.append(task);
}
}
return true;
}
// ==================== 枚举转换函数 ====================
QString TimedDataCollectionDataStructuresReaderWriter::taskStatusToString(TaskStatus status)
{
switch (status) {
case TaskStatus::Waiting: return "Waiting";
case TaskStatus::Running: return "Running";
case TaskStatus::Finished: return "Finished";
default: return "Waiting";
}
}
TaskStatus TimedDataCollectionDataStructuresReaderWriter::stringToTaskStatus(const QString& str)
{
if (str == "Running") return TaskStatus::Running;
if (str == "Finished") return TaskStatus::Finished;
return TaskStatus::Waiting;
}
QString TimedDataCollectionDataStructuresReaderWriter::subTaskTypeToString(SubTaskType type)
{
switch (type) {
case SubTaskType::HyperSpectual400_1000nm: return "HyperSpectual400_1000nm";
case SubTaskType::HyperSpectual1000_1700nm: return "HyperSpectual1000_1700nm";
case SubTaskType::SingleLensReflex: return "SingleLensReflex";
case SubTaskType::DepthCamera: return "DepthCamera";
default: return "Unknown";
}
}
SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(const QString& str)
{
if (str == "HyperSpectual400_1000nm") return SubTaskType::HyperSpectual400_1000nm;
if (str == "HyperSpectual1000_1700nm") return SubTaskType::HyperSpectual1000_1700nm;
if (str == "SingleLensReflex") return SubTaskType::SingleLensReflex;
if (str == "DepthCamera") return SubTaskType::DepthCamera;
return SubTaskType::SingleLensReflex;
}
// ==================== SubTask序列化 ====================
QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const SubTask& subTask)
{
QJsonObject obj;
obj["type"] = subTaskTypeToString(subTask.type);
obj["startTime"] = subTask.startTime.toString(Qt::ISODate);
obj["endTime"] = subTask.endTime.toString(Qt::ISODate);
obj["durationSeconds"] = subTask.durationSeconds;
obj["estimatedDurationSeconds"] = subTask.estimatedDurationSeconds;
obj["pathLineFilePath"] = subTask.pathLineFilePath;
obj["status"] = taskStatusToString(subTask.status);
obj["frameRate"] = subTask.frameRate;
obj["exposureTime"] = subTask.exposureTime;
obj["defaultRenderBand"] = subTask.defaultRenderBand;
obj["captureIntervalSeconds"] = subTask.captureIntervalSeconds;
return obj;
}
bool TimedDataCollectionDataStructuresReaderWriter::jsonToSubTask(const QJsonObject& json, SubTask& subTask)
{
subTask.type = stringToSubTaskType(json["type"].toString());
subTask.startTime = QDateTime::fromString(json["startTime"].toString(), Qt::ISODate);
subTask.endTime = QDateTime::fromString(json["endTime"].toString(), Qt::ISODate);
subTask.durationSeconds = json["durationSeconds"].toInt();
subTask.estimatedDurationSeconds = json["estimatedDurationSeconds"].toInt();
subTask.pathLineFilePath = json["pathLineFilePath"].toString();
subTask.status = stringToTaskStatus(json["status"].toString());
subTask.frameRate = json["frameRate"].toDouble();
subTask.exposureTime = json["exposureTime"].toDouble();
subTask.defaultRenderBand = json["defaultRenderBand"].toInt();
subTask.captureIntervalSeconds = json["captureIntervalSeconds"].toInt();
return true;
}
// ==================== TimedTask序列化 ====================
QJsonObject TimedDataCollectionDataStructuresReaderWriter::timedTaskToJson(const TimedTask& task)
{
QJsonObject obj;
obj["id"] = task.id;
obj["scheduledTime"] = task.scheduledTime.toString(Qt::ISODate);
obj["startTime"] = task.startTime.toString(Qt::ISODate);
obj["endTime"] = task.endTime.toString(Qt::ISODate);
obj["durationSeconds"] = task.durationSeconds;
obj["savePath"] = task.savePath;
obj["status"] = taskStatusToString(task.status);
QJsonArray subTasksArray;
for (const auto& subTask : task.subTasks) {
subTasksArray.append(subTaskToJson(subTask));
}
obj["subTasks"] = subTasksArray;
return obj;
}
bool TimedDataCollectionDataStructuresReaderWriter::jsonToTimedTask(const QJsonObject& json, TimedTask& task)
{
task.id = json["id"].toInt();
task.scheduledTime = QDateTime::fromString(json["scheduledTime"].toString(), Qt::ISODate);
task.startTime = QDateTime::fromString(json["startTime"].toString(), Qt::ISODate);
task.endTime = QDateTime::fromString(json["endTime"].toString(), Qt::ISODate);
task.durationSeconds = json["durationSeconds"].toInt();
task.savePath = json["savePath"].toString();
task.status = stringToTaskStatus(json["status"].toString());
QJsonArray subTasksArray = json["subTasks"].toArray();
task.subTasks.clear();
task.subTasks.reserve(subTasksArray.size());
for (const auto& subTaskValue : subTasksArray) {
if (!subTaskValue.isObject()) continue;
SubTask subTask;
if (jsonToSubTask(subTaskValue.toObject(), subTask)) {
task.subTasks.append(subTask);
}
}
return true;
}

View File

@ -0,0 +1,104 @@
#pragma once
#include <QDateTime>
#include <QString>
#include <QVector>
#include <QMetaType>
// ==================== 枚举定义 ====================
// 任务状态
enum class TaskStatus {
Waiting, // 等待
Running, // 运行中
Finished // 结束
};
// 子任务类型
enum class SubTaskType {
HyperSpectual400_1000nm, // 400nm-1000nm高光谱相机
HyperSpectual1000_1700nm, // 1000nm-1700nm高光谱相机
SingleLensReflex, // 单反相机
DepthCamera // 深度相机
};
// ==================== 统一子任务封装 ====================
struct SubTask {
SubTaskType type; // 子任务类型
// 共享属性
QDateTime startTime;
QDateTime endTime;
int durationSeconds = 0;
int estimatedDurationSeconds = 0;
QString pathLineFilePath;
TaskStatus status = TaskStatus::Waiting;
// 类型特有属性根据type选择使用
double frameRate = 0.0; // 高光谱相机用
double exposureTime = 0.0; // 高光谱相机用
int defaultRenderBand = 550; // 1000-1700nm高光谱用
int captureIntervalSeconds = 5; // 单反/深度相机用
};
// ==================== 定时任务 ====================
struct TimedTask {
int id = 0; // 任务ID
QDateTime scheduledTime; // 计划时间
QDateTime startTime; // 开始时间
QDateTime endTime; // 结束时间
int durationSeconds = 0; // 耗时(秒)
QString savePath; // 数据保存路径
QVector<SubTask> subTasks; // 子任务列表
TaskStatus status = TaskStatus::Waiting; // 状态
// 计算所有子任务的预计总时间
int totalEstimatedDuration() const {
int total = 0;
for (const auto& subTask : subTasks) {
total += subTask.estimatedDurationSeconds;
}
return total;
}
// 获取子任务数量
int subTaskCount() const {
return subTasks.size();
}
};
// ==================== Qt元类型声明 ====================
Q_DECLARE_METATYPE(TaskStatus)
Q_DECLARE_METATYPE(SubTaskType)
Q_DECLARE_METATYPE(SubTask)
Q_DECLARE_METATYPE(TimedTask)
// ==================== 任务文件读写类 ====================
class TimedDataCollectionDataStructuresReaderWriter
{
public:
// 保存任务到文件
static bool saveTasksToFile(const QString& filePath, const QVector<TimedTask>& tasks);
// 从文件读取任务
static bool loadTasksFromFile(const QString& filePath, QVector<TimedTask>& tasks);
private:
// SubTask序列化
static QJsonObject subTaskToJson(const SubTask& subTask);
static bool jsonToSubTask(const QJsonObject& json, SubTask& subTask);
// TimedTask序列化
static QJsonObject timedTaskToJson(const TimedTask& task);
static bool jsonToTimedTask(const QJsonObject& json, TimedTask& task);
// 枚举转换
static QString taskStatusToString(TaskStatus status);
static TaskStatus stringToTaskStatus(const QString& str);
static QString subTaskTypeToString(SubTaskType type);
static SubTaskType stringToSubTaskType(const QString& str);
};