add,计划采集13:
优化逻辑
This commit is contained in:
@ -576,7 +576,7 @@ HPPA::HPPA(QWidget* parent)
|
||||
initMapTools();
|
||||
|
||||
//定时采集
|
||||
initTimedDataCollection();
|
||||
connect(this->ui.mActionTimedDataCollection, SIGNAL(triggered()), this, SLOT(onTimedDataCollection()));
|
||||
|
||||
QString strPath = QCoreApplication::applicationDirPath() + "/UILayout.ini";
|
||||
QFile file(strPath);
|
||||
@ -593,22 +593,26 @@ HPPA::HPPA(QWidget* parent)
|
||||
|
||||
void HPPA::initTimedDataCollection()
|
||||
{
|
||||
connect(this->ui.mActionTimedDataCollection, SIGNAL(triggered()), this, SLOT(onTimedDataCollection()));
|
||||
mTimedDataCollectionWindow = new TimedDataCollection();
|
||||
TimedDataCollection mTimedDataCollectionWindow;
|
||||
|
||||
m_tmc->onConnectMotor();
|
||||
|
||||
// 定时采集控制器 → 相机/马达
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::hyperCamParm, this, &HPPA::setTimedDataCollectionHyperCamParm);
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::camParm, this, &HPPA::setTimedDataCollectionCamParm);
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::motorParm, this, &HPPA::setTimedDataCollectionMotorParm);
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::startRecordSignal, this, &HPPA::onStartTimedDataCollection);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::hyperCamParm, this, &HPPA::setTimedDataCollectionHyperCamParm);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::camParm, this, &HPPA::setTimedDataCollectionCamParm);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::motorParm, this, &HPPA::setTimedDataCollectionMotorParm);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::startRecordSignal, this, &HPPA::onStartTimedDataCollection);
|
||||
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::switchHalogenLampSignal, m_pc3D, &PowerControl3D::switchHalogenLampPower);
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::switchD65LampSignal, m_pc3D, &PowerControl3D::switchD65LampPower);
|
||||
connect(mTimedDataCollectionWindow, &TimedDataCollection::switchSlrSignal, m_pc3D, &PowerControl3D::switchSlrPower);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::switchHalogenLampSignal, m_pc3D, &PowerControl3D::switchHalogenLampPower);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::switchD65LampSignal, m_pc3D, &PowerControl3D::switchD65LampPower);
|
||||
connect(&mTimedDataCollectionWindow, &TimedDataCollection::switchSlrSignal, m_pc3D, &PowerControl3D::switchSlrPower);
|
||||
|
||||
// 相机/马达 → 定时采集控制器
|
||||
connect(m_tmc, &TwoMotorControl::sequenceComplete, mTimedDataCollectionWindow, &TimedDataCollection::subTaskCompleted);
|
||||
connect(m_tmc, &TwoMotorControl::back2OriginSignal_TimedDataCollection, mTimedDataCollectionWindow, &TimedDataCollection::onBack2Origin);
|
||||
connect(m_tmc, &TwoMotorControl::sequenceComplete, &mTimedDataCollectionWindow, &TimedDataCollection::subTaskCompleted);
|
||||
connect(m_tmc, &TwoMotorControl::back2OriginSignal_TimedDataCollection, &mTimedDataCollectionWindow, &TimedDataCollection::onBack2Origin);
|
||||
|
||||
mTimedDataCollectionWindow.show();
|
||||
mTimedDataCollectionWindow.exec();
|
||||
}
|
||||
|
||||
void HPPA::setTimedDataCollectionHyperCamParm(int camType, double f, double e, QString filePath, QString fileName)
|
||||
@ -716,8 +720,7 @@ void HPPA::onTimedDataCollection()
|
||||
QString checkedScenarioName = checkedScenario->objectName();
|
||||
if (checkedScenarioName == "mAction3DPlantPhenotypeScenario")//计划采集
|
||||
{
|
||||
mTimedDataCollectionWindow->show();
|
||||
//mTimedDataCollectionWindow->exec();
|
||||
initTimedDataCollection();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -321,7 +321,6 @@ private:
|
||||
bool showResultMessageBox(QString title, QString msg);
|
||||
void disconnectImagerAndCleanup();
|
||||
|
||||
TimedDataCollection* mTimedDataCollectionWindow;
|
||||
void initTimedDataCollection();
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
@ -140,6 +140,7 @@
|
||||
<ClCompile Include="MapToolSpectral.cpp" />
|
||||
<ClCompile Include="MotorWindowBase.cpp" />
|
||||
<ClCompile Include="OneMotorControl.cpp" />
|
||||
<ClCompile Include="PathLine.cpp" />
|
||||
<ClCompile Include="path_tc.cpp" />
|
||||
<ClCompile Include="PowerControl.cpp" />
|
||||
<ClCompile Include="PowerControl3D.cpp" />
|
||||
@ -252,6 +253,7 @@
|
||||
<QtMoc Include="MapTools.h" />
|
||||
<ClInclude Include="MotorWindowBase.h" />
|
||||
<QtMoc Include="PowerControl3D.h" />
|
||||
<ClInclude Include="PathLine.h" />
|
||||
<ClInclude Include="RasterDataProvider.h" />
|
||||
<ClInclude Include="MultibandRasterRenderer.h" />
|
||||
<ClInclude Include="RasterImageLayer.h" />
|
||||
|
||||
@ -250,6 +250,9 @@
|
||||
<ClCompile Include="TaskTreeModel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PathLine.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="fileOperation.h">
|
||||
@ -467,6 +470,9 @@
|
||||
<ClInclude Include="MotorWindowBase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PathLine.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="FocusDialog.ui">
|
||||
|
||||
319
HPPA/PathLine.cpp
Normal file
319
HPPA/PathLine.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
#include "PathLine.h"
|
||||
#include <QTableWidgetItem>
|
||||
#include <cstdio>
|
||||
|
||||
PathLineManager::PathLineManager()
|
||||
{
|
||||
}
|
||||
|
||||
PathLineManager::~PathLineManager()
|
||||
{
|
||||
}
|
||||
|
||||
QVector<PathLine2> PathLineManager::readFromTableWidget(QTableWidget* tableWidget)
|
||||
{
|
||||
QVector<PathLine2> pathLines;
|
||||
|
||||
if (tableWidget == nullptr)
|
||||
return pathLines;
|
||||
|
||||
int rowCount = tableWidget->rowCount();
|
||||
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
PathLine2 tmp;
|
||||
|
||||
tmp.targetYPosition = tableWidget->item(i, 0)->text().toDouble();
|
||||
tmp.speedTargetYPosition = tableWidget->item(i, 1)->text().toDouble();
|
||||
tmp.targetXMinPosition = tableWidget->item(i, 2)->text().toDouble();
|
||||
tmp.speedTargetXMinPosition = tableWidget->item(i, 3)->text().toDouble();
|
||||
tmp.targetXMaxPosition = tableWidget->item(i, 4)->text().toDouble();
|
||||
tmp.speedTargetXMaxPosition = tableWidget->item(i, 5)->text().toDouble();
|
||||
|
||||
pathLines.append(tmp);
|
||||
}
|
||||
|
||||
return pathLines;
|
||||
}
|
||||
|
||||
void PathLineManager::writeToTableWidget(QTableWidget* tableWidget, const QVector<PathLine2>& pathLines)
|
||||
{
|
||||
if (tableWidget == nullptr)
|
||||
return;
|
||||
|
||||
// 清空现有行
|
||||
int rowCount = tableWidget->rowCount();
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
tableWidget->removeRow(0);
|
||||
}
|
||||
|
||||
// 添加新行
|
||||
for (int i = 0; i < pathLines.size(); i++)
|
||||
{
|
||||
tableWidget->insertRow(i);
|
||||
|
||||
QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(pathLines[i].targetYPosition, 'f', 5));
|
||||
QTableWidgetItem* item1 = new QTableWidgetItem(QString::number(pathLines[i].speedTargetYPosition, 'f', 5));
|
||||
QTableWidgetItem* item2 = new QTableWidgetItem(QString::number(pathLines[i].targetXMinPosition, 'f', 5));
|
||||
QTableWidgetItem* item3 = new QTableWidgetItem(QString::number(pathLines[i].speedTargetXMinPosition, 'f', 5));
|
||||
QTableWidgetItem* item4 = new QTableWidgetItem(QString::number(pathLines[i].targetXMaxPosition, 'f', 5));
|
||||
QTableWidgetItem* item5 = new QTableWidgetItem(QString::number(pathLines[i].speedTargetXMaxPosition, 'f', 5));
|
||||
|
||||
item0->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item1->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item2->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item3->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item4->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item5->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
|
||||
tableWidget->setItem(i, 0, item0);
|
||||
tableWidget->setItem(i, 1, item1);
|
||||
tableWidget->setItem(i, 2, item2);
|
||||
tableWidget->setItem(i, 3, item3);
|
||||
tableWidget->setItem(i, 4, item4);
|
||||
tableWidget->setItem(i, 5, item5);
|
||||
}
|
||||
}
|
||||
|
||||
bool PathLineManager::saveToFile(const QString& filePath, QTableWidget* tableWidget)
|
||||
{
|
||||
if (tableWidget == nullptr || tableWidget->rowCount() <= 0)
|
||||
return false;
|
||||
|
||||
FILE* fileHandle = fopen(filePath.toStdString().c_str(), "wb+");
|
||||
if (fileHandle == nullptr)
|
||||
return false;
|
||||
|
||||
double number = tableWidget->rowCount() * tableWidget->columnCount();
|
||||
fwrite(&number, sizeof(double), 1, fileHandle);
|
||||
|
||||
double* data = new double[static_cast<int>(number)];
|
||||
|
||||
for (int i = 0; i < tableWidget->rowCount(); i++)
|
||||
{
|
||||
for (int j = 0; j < tableWidget->columnCount(); j++)
|
||||
{
|
||||
data[i * tableWidget->columnCount() + j] = tableWidget->item(i, j)->text().toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(data, sizeof(double), static_cast<size_t>(number), fileHandle);
|
||||
|
||||
fclose(fileHandle);
|
||||
delete[] data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PathLineManager::saveToFile(const QString& filePath, const QVector<PathLine2>& pathLines)
|
||||
{
|
||||
if (pathLines.isEmpty())
|
||||
return false;
|
||||
|
||||
FILE* fileHandle = fopen(filePath.toStdString().c_str(), "wb+");
|
||||
if (fileHandle == nullptr)
|
||||
return false;
|
||||
|
||||
double number = pathLines.size() * COLUMN_COUNT;
|
||||
fwrite(&number, sizeof(double), 1, fileHandle);
|
||||
|
||||
double* data = new double[static_cast<int>(number)];
|
||||
|
||||
for (int i = 0; i < pathLines.size(); i++)
|
||||
{
|
||||
data[i * COLUMN_COUNT + 0] = pathLines[i].targetYPosition;
|
||||
data[i * COLUMN_COUNT + 1] = pathLines[i].speedTargetYPosition;
|
||||
data[i * COLUMN_COUNT + 2] = pathLines[i].targetXMinPosition;
|
||||
data[i * COLUMN_COUNT + 3] = pathLines[i].speedTargetXMinPosition;
|
||||
data[i * COLUMN_COUNT + 4] = pathLines[i].targetXMaxPosition;
|
||||
data[i * COLUMN_COUNT + 5] = pathLines[i].speedTargetXMaxPosition;
|
||||
}
|
||||
|
||||
fwrite(data, sizeof(double), static_cast<size_t>(number), fileHandle);
|
||||
|
||||
fclose(fileHandle);
|
||||
delete[] data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PathLineManager::readFromFile(const QString& filePath, QTableWidget* tableWidget)
|
||||
{
|
||||
if (tableWidget == nullptr)
|
||||
return false;
|
||||
|
||||
FILE* fileHandle = fopen(filePath.toStdString().c_str(), "rb");
|
||||
if (fileHandle == nullptr)
|
||||
return false;
|
||||
|
||||
double number;
|
||||
fread(&number, sizeof(double), 1, fileHandle);
|
||||
|
||||
double* data = new double[static_cast<int>(number)];
|
||||
for (int i = 0; i < static_cast<int>(number); i++)
|
||||
{
|
||||
fread(data + i, sizeof(double), 1, fileHandle);
|
||||
}
|
||||
|
||||
// 清空现有行
|
||||
int rowCount = tableWidget->rowCount();
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
tableWidget->removeRow(0);
|
||||
}
|
||||
|
||||
// 添加新行
|
||||
int recordLineCount = static_cast<int>(number) / tableWidget->columnCount();
|
||||
for (int i = 0; i < recordLineCount; i++)
|
||||
{
|
||||
tableWidget->insertRow(i);
|
||||
}
|
||||
|
||||
// 填充数据
|
||||
for (int i = 0; i < tableWidget->rowCount(); i++)
|
||||
{
|
||||
for (int j = 0; j < tableWidget->columnCount(); j++)
|
||||
{
|
||||
QTableWidgetItem* tmp = new QTableWidgetItem(
|
||||
QString::number(data[i * tableWidget->columnCount() + j], 'f', 5));
|
||||
tmp->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
tableWidget->setItem(i, j, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fileHandle);
|
||||
delete[] data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<PathLine2> PathLineManager::readFromFile(const QString& filePath, bool* success)
|
||||
{
|
||||
QVector<PathLine2> pathLines;
|
||||
|
||||
FILE* fileHandle = fopen(filePath.toStdString().c_str(), "rb");
|
||||
if (fileHandle == nullptr)
|
||||
{
|
||||
if (success) *success = false;
|
||||
return pathLines;
|
||||
}
|
||||
|
||||
double number;
|
||||
fread(&number, sizeof(double), 1, fileHandle);
|
||||
|
||||
double* data = new double[static_cast<int>(number)];
|
||||
for (int i = 0; i < static_cast<int>(number); i++)
|
||||
{
|
||||
fread(data + i, sizeof(double), 1, fileHandle);
|
||||
}
|
||||
|
||||
int recordLineCount = static_cast<int>(number) / COLUMN_COUNT;
|
||||
for (int i = 0; i < recordLineCount; i++)
|
||||
{
|
||||
PathLine2 tmp;
|
||||
tmp.targetYPosition = data[i * COLUMN_COUNT + 0];
|
||||
tmp.speedTargetYPosition = data[i * COLUMN_COUNT + 1];
|
||||
tmp.targetXMinPosition = data[i * COLUMN_COUNT + 2];
|
||||
tmp.speedTargetXMinPosition = data[i * COLUMN_COUNT + 3];
|
||||
tmp.targetXMaxPosition = data[i * COLUMN_COUNT + 4];
|
||||
tmp.speedTargetXMaxPosition = data[i * COLUMN_COUNT + 5];
|
||||
|
||||
pathLines.append(tmp);
|
||||
}
|
||||
|
||||
fclose(fileHandle);
|
||||
delete[] data;
|
||||
|
||||
if (success) *success = true;
|
||||
return pathLines;
|
||||
}
|
||||
|
||||
void PathLineManager::addRecordLine(QTableWidget* tableWidget,
|
||||
double yPos, double ySpeed,
|
||||
double xMinPos, double xMinSpeed,
|
||||
double xMaxPos, double xMaxSpeed)
|
||||
{
|
||||
if (tableWidget == nullptr)
|
||||
return;
|
||||
|
||||
int currentRow = tableWidget->currentRow();
|
||||
int insertRow = (currentRow == -1) ? tableWidget->rowCount() : currentRow + 1;
|
||||
|
||||
tableWidget->insertRow(insertRow);
|
||||
|
||||
QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(yPos, 'f', 2));
|
||||
QTableWidgetItem* item1 = new QTableWidgetItem(QString::number(ySpeed, 'f', 2));
|
||||
QTableWidgetItem* item2 = new QTableWidgetItem(QString::number(xMinPos, 'f', 2));
|
||||
QTableWidgetItem* item3 = new QTableWidgetItem(QString::number(xMinSpeed, 'f', 2));
|
||||
QTableWidgetItem* item4 = new QTableWidgetItem(QString::number(xMaxPos, 'f', 2));
|
||||
QTableWidgetItem* item5 = new QTableWidgetItem(QString::number(xMaxSpeed, 'f', 2));
|
||||
|
||||
item0->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item1->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item2->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item3->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item4->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
item5->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
|
||||
tableWidget->setItem(insertRow, 0, item0);
|
||||
tableWidget->setItem(insertRow, 1, item1);
|
||||
tableWidget->setItem(insertRow, 2, item2);
|
||||
tableWidget->setItem(insertRow, 3, item3);
|
||||
tableWidget->setItem(insertRow, 4, item4);
|
||||
tableWidget->setItem(insertRow, 5, item5);
|
||||
}
|
||||
|
||||
double PathLineManager::calculateTimeFromFile(const QString& filePath)
|
||||
{
|
||||
bool success = false;
|
||||
QVector<PathLine2> pathLines = readFromFile(filePath, &success);
|
||||
if (!success || pathLines.isEmpty())
|
||||
return 0.0;
|
||||
|
||||
double totalTimeSecond = 0.0;
|
||||
double currentX = 0.0;
|
||||
double currentY = 0.0;
|
||||
double yTime;
|
||||
double xTime;
|
||||
|
||||
for (int i = 0; i < pathLines.size(); i++)
|
||||
{
|
||||
const PathLine2& line = pathLines[i];
|
||||
|
||||
double yDistance = qAbs(line.targetYPosition - currentY);
|
||||
if (line.speedTargetYPosition > 0.0 && yDistance > 0.0)
|
||||
{
|
||||
yTime = yDistance / line.speedTargetYPosition;
|
||||
}
|
||||
double xMinDistance = qAbs(line.targetXMinPosition - currentX);
|
||||
if (line.speedTargetXMinPosition > 0.0 && xMinDistance > 0.0)
|
||||
{
|
||||
xTime = xMinDistance / line.speedTargetXMinPosition;
|
||||
}
|
||||
totalTimeSecond += std::max(yTime, xTime);
|
||||
|
||||
double xMaxDistance = qAbs(line.targetXMaxPosition - line.targetXMinPosition);
|
||||
if (line.speedTargetXMaxPosition > 0.0 && xMaxDistance > 0.0)
|
||||
{
|
||||
totalTimeSecond += xMaxDistance / line.speedTargetXMaxPosition;
|
||||
}
|
||||
|
||||
currentX = line.targetXMaxPosition;
|
||||
currentY = line.targetYPosition;
|
||||
}
|
||||
|
||||
double returnYDistance = currentY;
|
||||
double returnXDistance = currentX;
|
||||
if (currentY > 0.0)
|
||||
{
|
||||
yTime += returnYDistance / pathLines[0].speedTargetYPosition;
|
||||
}
|
||||
if (currentX > 0.0)
|
||||
{
|
||||
xTime += returnXDistance / pathLines[0].speedTargetXMinPosition;
|
||||
}
|
||||
totalTimeSecond += std::max(yTime, xTime);
|
||||
|
||||
return totalTimeSecond / 60;
|
||||
}
|
||||
51
HPPA/PathLine.h
Normal file
51
HPPA/PathLine.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QTableWidget>
|
||||
|
||||
// PathLine 结构体定义(如果还没有在其他地方定义)
|
||||
struct PathLine2
|
||||
{
|
||||
double targetYPosition;
|
||||
double speedTargetYPosition;
|
||||
double targetXMinPosition;
|
||||
double speedTargetXMinPosition;
|
||||
double targetXMaxPosition;
|
||||
double speedTargetXMaxPosition;
|
||||
};
|
||||
|
||||
class PathLineManager
|
||||
{
|
||||
public:
|
||||
PathLineManager();
|
||||
~PathLineManager();
|
||||
|
||||
// 从TableWidget读取PathLine数据
|
||||
static QVector<PathLine2> readFromTableWidget(QTableWidget* tableWidget);
|
||||
|
||||
// 将PathLine数据写入TableWidget
|
||||
static void writeToTableWidget(QTableWidget* tableWidget, const QVector<PathLine2>& pathLines);
|
||||
|
||||
// 保存PathLine到文件
|
||||
static bool saveToFile(const QString& filePath, QTableWidget* tableWidget);
|
||||
static bool saveToFile(const QString& filePath, const QVector<PathLine2>& pathLines);
|
||||
|
||||
// 从文件读取PathLine
|
||||
static bool readFromFile(const QString& filePath, QTableWidget* tableWidget);
|
||||
static QVector<PathLine2> readFromFile(const QString& filePath, bool* success = nullptr);
|
||||
|
||||
// 添加一行PathLine到TableWidget
|
||||
static void addRecordLine(QTableWidget* tableWidget,
|
||||
double yPos = 15.0,
|
||||
double ySpeed = 1.0,
|
||||
double xMinPos = 0.0,
|
||||
double xMinSpeed = 1.0,
|
||||
double xMaxPos = 50.0,
|
||||
double xMaxSpeed = 1.0);
|
||||
|
||||
static double calculateTimeFromFile(const QString& filePath);
|
||||
|
||||
private:
|
||||
static const int COLUMN_COUNT = 6;
|
||||
};
|
||||
@ -50,12 +50,16 @@ TreeNode* TreeNode::parentNode()
|
||||
TaskTreeModel::TaskTreeModel(QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
, m_rootNode(new TreeNode())
|
||||
, m_countdownTimer(new QTimer(this))
|
||||
{
|
||||
m_rootNode->nodeType = TreeNodeType::Root;
|
||||
m_countdownTimer->setInterval(1000);
|
||||
connect(m_countdownTimer, &QTimer::timeout, this, &TaskTreeModel::onCountdownTimerTimeout);
|
||||
}
|
||||
|
||||
TaskTreeModel::~TaskTreeModel()
|
||||
{
|
||||
m_countdownTimer->stop();
|
||||
delete m_rootNode;
|
||||
}
|
||||
|
||||
@ -123,6 +127,18 @@ QVariant TaskTreeModel::data(const QModelIndex& index, int role) const
|
||||
return QString::fromLocal8Bit("定时任务 %1").arg(task.id);
|
||||
case ColScheduledTime:
|
||||
return task.scheduledTime.toString("yyyy-MM-dd HH:mm:ss");
|
||||
case ColCountdown: {
|
||||
if (task.status == TaskStatus::Finished || task.status == TaskStatus::Running)
|
||||
{
|
||||
return QString::fromLocal8Bit("0");
|
||||
}
|
||||
qint64 seconds = QDateTime::currentDateTime().secsTo(task.scheduledTime);
|
||||
if (seconds < 0)
|
||||
{
|
||||
return QString::fromLocal8Bit("已超时");
|
||||
}
|
||||
return formatCountdown(seconds);
|
||||
}
|
||||
case ColStartTime:
|
||||
return task.startTime.isValid() ?
|
||||
task.startTime.toString("HH:mm:ss") : "-";
|
||||
@ -131,6 +147,8 @@ QVariant TaskTreeModel::data(const QModelIndex& index, int role) const
|
||||
task.endTime.toString("HH:mm:ss") : "-";
|
||||
case ColDuration:
|
||||
return formatDuration(task.durationMinutes);
|
||||
case ColEstimatedDuration:
|
||||
return formatDuration(task.estimatedDurationMinutes);
|
||||
case ColStatus:
|
||||
return statusToString(task.status);
|
||||
case ColProgress: {
|
||||
@ -151,6 +169,8 @@ QVariant TaskTreeModel::data(const QModelIndex& index, int role) const
|
||||
return subTaskTypeToString(subTask.type);
|
||||
case ColScheduledTime:
|
||||
return "-";
|
||||
case ColCountdown:
|
||||
return "-";
|
||||
case ColStartTime:
|
||||
return subTask.startTime.isValid() ?
|
||||
subTask.startTime.toString("HH:mm:ss") : "-";
|
||||
@ -159,6 +179,8 @@ QVariant TaskTreeModel::data(const QModelIndex& index, int role) const
|
||||
subTask.endTime.toString("HH:mm:ss") : "-";
|
||||
case ColDuration:
|
||||
return formatDuration(subTask.durationMinutes);
|
||||
case ColEstimatedDuration:
|
||||
return formatDuration(subTask.estimatedDurationMinutes);
|
||||
case ColStatus:
|
||||
return statusToString(subTask.status);
|
||||
case ColProgress:
|
||||
@ -265,9 +287,11 @@ QVariant TaskTreeModel::headerData(int section, Qt::Orientation orientation, int
|
||||
switch (section) {
|
||||
case ColName: return QString::fromLocal8Bit("名称");
|
||||
case ColScheduledTime: return QString::fromLocal8Bit("计划时间");
|
||||
case ColCountdown: return QString::fromLocal8Bit("倒计时");
|
||||
case ColStartTime: return QString::fromLocal8Bit("开始时间");
|
||||
case ColEndTime: return QString::fromLocal8Bit("结束时间");
|
||||
case ColDuration: return QString::fromLocal8Bit("耗时");
|
||||
case ColEstimatedDuration: return QString::fromLocal8Bit("预测耗时");
|
||||
case ColStatus: return QString::fromLocal8Bit("状态");
|
||||
case ColProgress: return QString::fromLocal8Bit("进度");
|
||||
case ColPath: return QString::fromLocal8Bit("路径");
|
||||
@ -285,6 +309,8 @@ Qt::ItemFlags TaskTreeModel::flags(const QModelIndex& index) const
|
||||
|
||||
void TaskTreeModel::setTasks(const QVector<TimedTask>& tasks)
|
||||
{
|
||||
m_countdownTimer->stop();
|
||||
|
||||
beginResetModel();
|
||||
|
||||
m_tasks = tasks;
|
||||
@ -292,6 +318,8 @@ void TaskTreeModel::setTasks(const QVector<TimedTask>& tasks)
|
||||
setupModelData();
|
||||
|
||||
endResetModel();
|
||||
|
||||
m_countdownTimer->start();
|
||||
}
|
||||
|
||||
void TaskTreeModel::setupModelData()
|
||||
@ -400,6 +428,19 @@ void TaskTreeModel::updateSubTask(int taskId, int subTaskIndex, const SubTask& s
|
||||
emit subTaskUpdated(taskId, subTaskIndex);
|
||||
}
|
||||
|
||||
void TaskTreeModel::setTaskAndSubtaskStatus(int taskId, TaskStatus status)
|
||||
{
|
||||
int dataIndex = findTaskDataIndex(taskId);
|
||||
if (dataIndex < 0) return;
|
||||
|
||||
updateTaskStatus(taskId, status);
|
||||
|
||||
for (size_t i = 0; i < m_tasks[dataIndex].subTaskCount(); i++)
|
||||
{
|
||||
updateSubTaskStatus(taskId, i, status);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskTreeModel::updateTaskStatus(int taskId, TaskStatus status)
|
||||
{
|
||||
int dataIndex = findTaskDataIndex(taskId);
|
||||
@ -407,17 +448,6 @@ void TaskTreeModel::updateTaskStatus(int taskId, TaskStatus status)
|
||||
|
||||
m_tasks[dataIndex].status = status;
|
||||
|
||||
if (status == TaskStatus::Running) {
|
||||
m_tasks[dataIndex].startTime = QDateTime::currentDateTime();
|
||||
}
|
||||
else if (status == TaskStatus::Finished) {
|
||||
m_tasks[dataIndex].endTime = QDateTime::currentDateTime();
|
||||
if (m_tasks[dataIndex].startTime.isValid()) {
|
||||
m_tasks[dataIndex].durationMinutes =
|
||||
m_tasks[dataIndex].startTime.secsTo(m_tasks[dataIndex].endTime) / 60.0;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex taskIndex = getTaskIndex(taskId);
|
||||
if (taskIndex.isValid()) {
|
||||
QModelIndex topLeft = index(taskIndex.row(), 0, taskIndex.parent());
|
||||
@ -426,6 +456,12 @@ void TaskTreeModel::updateTaskStatus(int taskId, TaskStatus status)
|
||||
}
|
||||
}
|
||||
|
||||
void TaskTreeModel::updateSubTaskStatusAndProgress(int taskId, int subTaskIndex, TaskStatus status)
|
||||
{
|
||||
updateSubTaskStatus(taskId, subTaskIndex, status);
|
||||
updateProgress(taskId);
|
||||
}
|
||||
|
||||
void TaskTreeModel::updateSubTaskStatus(int taskId, int subTaskIndex, TaskStatus status)
|
||||
{
|
||||
int dataIndex = findTaskDataIndex(taskId);
|
||||
@ -435,23 +471,16 @@ void TaskTreeModel::updateSubTaskStatus(int taskId, int subTaskIndex, TaskStatus
|
||||
SubTask& subTask = m_tasks[dataIndex].subTasks[subTaskIndex];
|
||||
subTask.status = status;
|
||||
|
||||
if (status == TaskStatus::Running) {
|
||||
subTask.startTime = QDateTime::currentDateTime();
|
||||
}
|
||||
else if (status == TaskStatus::Finished) {
|
||||
subTask.endTime = QDateTime::currentDateTime();
|
||||
if (subTask.startTime.isValid()) {
|
||||
subTask.durationMinutes = subTask.startTime.secsTo(subTask.endTime) / 60.0;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex subTaskModelIndex = getSubTaskIndex(taskId, subTaskIndex);
|
||||
if (subTaskModelIndex.isValid()) {
|
||||
QModelIndex topLeft = index(subTaskModelIndex.row(), 0, subTaskModelIndex.parent());
|
||||
QModelIndex bottomRight = index(subTaskModelIndex.row(), ColumnCount - 1, subTaskModelIndex.parent());
|
||||
emit dataChanged(topLeft, bottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskTreeModel::updateProgress(int taskId)
|
||||
{
|
||||
// 更新父任务进度
|
||||
QModelIndex taskIndex = getTaskIndex(taskId);
|
||||
if (taskIndex.isValid()) {
|
||||
@ -534,12 +563,14 @@ int TaskTreeModel::findTaskDataIndex(int taskId) const
|
||||
QString TaskTreeModel::statusToString(TaskStatus status) const
|
||||
{
|
||||
switch (status) {
|
||||
case TaskStatus::default: return QString::fromLocal8Bit("未调度");
|
||||
case TaskStatus::Waiting: return QString::fromLocal8Bit("等待中");
|
||||
case TaskStatus::Running: return QString::fromLocal8Bit("运行中");
|
||||
case TaskStatus::Finished: return QString::fromLocal8Bit("已完成");
|
||||
case TaskStatus::Skiped: return QString::fromLocal8Bit("已跳过");
|
||||
case TaskStatus::Timeout: return QString::fromLocal8Bit("超时");
|
||||
}
|
||||
return "未知";
|
||||
return "";
|
||||
}
|
||||
|
||||
QString TaskTreeModel::subTaskTypeToString(SubTaskType type) const
|
||||
@ -582,3 +613,33 @@ QColor TaskTreeModel::statusColor(TaskStatus status) const
|
||||
}
|
||||
return QColor(255, 255, 255);
|
||||
}
|
||||
|
||||
QString TaskTreeModel::formatCountdown(qint64 seconds) const
|
||||
{
|
||||
if (seconds < 0) {
|
||||
return QString::fromLocal8Bit("已超时");
|
||||
}
|
||||
|
||||
int hours = static_cast<int>(seconds) / 3600;
|
||||
int mins = (static_cast<int>(seconds) % 3600) / 60;
|
||||
int secs = static_cast<int>(seconds) % 60;
|
||||
|
||||
return QString("%1:%2:%3")
|
||||
.arg(hours, 2, 10, QChar('0'))
|
||||
.arg(mins, 2, 10, QChar('0'))
|
||||
.arg(secs, 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
void TaskTreeModel::onCountdownTimerTimeout()
|
||||
{
|
||||
for (int i = 0; i < m_tasks.size(); ++i)
|
||||
{
|
||||
const TimedTask& task = m_tasks[i];
|
||||
QModelIndex taskIndex = getTaskIndex(task.id);
|
||||
if (taskIndex.isValid())
|
||||
{
|
||||
QModelIndex countdownIndex = index(taskIndex.row(), ColCountdown, taskIndex.parent());
|
||||
emit dataChanged(countdownIndex, countdownIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <QAbstractItemModel>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
#include <QTimer>
|
||||
#include "TimedDataCollectionDataStructures.h"
|
||||
|
||||
// 树节点类型
|
||||
@ -47,9 +48,11 @@ public:
|
||||
enum Column {
|
||||
ColName = 0, // 任务名称/子任务类型
|
||||
ColScheduledTime, // 计划时间
|
||||
ColCountdown, // 倒计时
|
||||
ColStartTime, // 开始时间
|
||||
ColEndTime, // 结束时间
|
||||
ColDuration, // 耗时
|
||||
ColEstimatedDuration, // 预测耗时
|
||||
ColStatus, // 状态
|
||||
ColProgress, // 进度(仅任务有效)
|
||||
ColPath, // 路径
|
||||
@ -73,7 +76,10 @@ public:
|
||||
void updateTask(const TimedTask& task);
|
||||
void updateSubTask(int taskId, int subTaskIndex, const SubTask& subTask);
|
||||
void updateTaskStatus(int taskId, TaskStatus status);
|
||||
void setTaskAndSubtaskStatus(int taskId, TaskStatus status);
|
||||
void updateSubTaskStatusAndProgress(int taskId, int subTaskIndex, TaskStatus status);
|
||||
void updateSubTaskStatus(int taskId, int subTaskIndex, TaskStatus status);
|
||||
void updateProgress(int taskId);
|
||||
|
||||
// 获取数据
|
||||
QVector<TimedTask>& tasks() { return m_tasks; }
|
||||
@ -89,6 +95,9 @@ signals:
|
||||
void taskUpdated(int taskId);
|
||||
void subTaskUpdated(int taskId, int subTaskIndex);
|
||||
|
||||
private slots:
|
||||
void onCountdownTimerTimeout();
|
||||
|
||||
private:
|
||||
void setupModelData();
|
||||
void clearTree();
|
||||
@ -100,7 +109,9 @@ private:
|
||||
QString subTaskTypeToString(SubTaskType type) const;
|
||||
QString formatDuration(double minutes) const;
|
||||
QColor statusColor(TaskStatus status) const;
|
||||
QString formatCountdown(qint64 seconds) const;
|
||||
|
||||
TreeNode* m_rootNode;
|
||||
QVector<TimedTask> m_tasks;
|
||||
QTimer* m_countdownTimer;
|
||||
};
|
||||
|
||||
@ -52,9 +52,11 @@ void TimedDataCollection::setupUI()
|
||||
// 设置列宽
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColName, 200);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColScheduledTime, 150);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColCountdown, 100);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColStartTime, 100);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColEndTime, 100);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColDuration, 100);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColEstimatedDuration, 100);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColStatus, 100);
|
||||
ui.taskTreeView->setColumnWidth(TaskTreeModel::ColProgress, 80);
|
||||
|
||||
@ -167,7 +169,7 @@ void TimedDataCollection::onSubTaskStarted(int taskId, int subTaskIndex)
|
||||
{
|
||||
m_currentSubTaskIndex = subTaskIndex;
|
||||
|
||||
m_taskModel->updateSubTaskStatus(taskId, subTaskIndex, TaskStatus::Running);
|
||||
m_taskModel->updateSubTaskStatusAndProgress(taskId, subTaskIndex, TaskStatus::Running);
|
||||
|
||||
// 滚动到当前子任务
|
||||
QModelIndex subTaskIndex_model = m_taskModel->getSubTaskIndex(taskId, subTaskIndex);
|
||||
@ -182,7 +184,7 @@ void TimedDataCollection::onSubTaskStarted(int taskId, int subTaskIndex)
|
||||
|
||||
void TimedDataCollection::onSubTaskFinished(int taskId, int subTaskIndex)
|
||||
{
|
||||
m_taskModel->updateSubTaskStatus(taskId, subTaskIndex, TaskStatus::Finished);
|
||||
m_taskModel->updateSubTaskStatusAndProgress(taskId, subTaskIndex, TaskStatus::Finished);
|
||||
|
||||
updateStatusBar();
|
||||
emit subTaskFinished(taskId, subTaskIndex);
|
||||
@ -396,11 +398,30 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
|
||||
if (TimedDataCollectionDataStructuresReaderWriter::loadTasksFromFile(filePath, loadedTasks)) {
|
||||
qDebug() << "Tasks loaded successfully, count:" << loadedTasks.size();
|
||||
|
||||
// 预测耗时:计算每个子任务和整个任务的预计耗时
|
||||
for (int i = 0; i < loadedTasks.size(); ++i)
|
||||
{
|
||||
double totalEstimatedMinutes = 0.0;
|
||||
for (int j = 0; j < loadedTasks[i].subTasks.size(); ++j)
|
||||
{
|
||||
QString pathLineFilePath = loadedTasks[i].subTasks[j].pathLineFilePath;
|
||||
if (!pathLineFilePath.isEmpty())
|
||||
{
|
||||
double estimatedMinutes = PathLineManager::calculateTimeFromFile(pathLineFilePath);
|
||||
loadedTasks[i].subTasks[j].estimatedDurationMinutes = estimatedMinutes;
|
||||
totalEstimatedMinutes += loadedTasks[i].subTasks[j].estimatedDurationMinutes;
|
||||
}
|
||||
}
|
||||
double slrTimeMinute = 135 / 60;
|
||||
loadedTasks[i].estimatedDurationMinutes = totalEstimatedMinutes + loadedTasks[i].HalogenLampPreheatingTime_Minute + slrTimeMinute;
|
||||
}
|
||||
|
||||
m_taskModel->setTasks(loadedTasks);
|
||||
ui.taskTreeView->expandAll(); // 默认展开所有任务
|
||||
|
||||
// 更新调度器
|
||||
if (m_scheduler) {
|
||||
if (m_scheduler)
|
||||
{
|
||||
m_scheduler->loadTasks(loadedTasks);
|
||||
}
|
||||
|
||||
@ -415,7 +436,18 @@ void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
|
||||
|
||||
void TimedDataCollection::startScheduler()
|
||||
{
|
||||
if (m_scheduler) {
|
||||
if (m_scheduler)
|
||||
{
|
||||
if (m_scheduler->isRunning())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_taskModel->tasks().size(); i++)
|
||||
{
|
||||
m_taskModel->setTaskAndSubtaskStatus(m_taskModel->tasks()[i].id, TaskStatus::Waiting);
|
||||
}
|
||||
|
||||
m_scheduler->loadTasks(m_taskModel->tasks());
|
||||
m_scheduler->start();
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "ui_TimedDataCollection_ui.h"
|
||||
#include "TimedDataCollectionDataStructures.h"
|
||||
#include "TaskTreeModel.h"
|
||||
#include "PathLine.h"
|
||||
|
||||
class TimedDataCollection : public QDialog
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDebug>
|
||||
#include <algorithm>
|
||||
|
||||
// ==================== 公共接口实现 ====================
|
||||
|
||||
@ -88,9 +89,9 @@ QString TimedDataCollectionDataStructuresReaderWriter::taskStatusToString(TaskSt
|
||||
|
||||
TaskStatus TimedDataCollectionDataStructuresReaderWriter::stringToTaskStatus(const QString& str)
|
||||
{
|
||||
if (str == "Running") return TaskStatus::Running;
|
||||
if (str == "Finished") return TaskStatus::Finished;
|
||||
return TaskStatus::Waiting;
|
||||
//if (str == "Running") return TaskStatus::Running;
|
||||
//if (str == "Finished") return TaskStatus::Finished;
|
||||
return TaskStatus::default;
|
||||
}
|
||||
|
||||
QString TimedDataCollectionDataStructuresReaderWriter::subTaskTypeToString(SubTaskType type)
|
||||
@ -135,8 +136,8 @@ QJsonObject TimedDataCollectionDataStructuresReaderWriter::subTaskToJson(const S
|
||||
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.startTime = QDateTime::fromString(QString(), Qt::ISODate);
|
||||
subTask.endTime = QDateTime::fromString(QString(), Qt::ISODate);
|
||||
subTask.durationMinutes = json["durationMinutes"].toDouble();
|
||||
subTask.estimatedDurationMinutes = json["estimatedDurationMinutes"].toDouble();
|
||||
subTask.pathLineFilePath = json["pathLineFilePath"].toString();
|
||||
@ -158,6 +159,7 @@ QJsonObject TimedDataCollectionDataStructuresReaderWriter::timedTaskToJson(const
|
||||
obj["startTime"] = task.startTime.toString(Qt::ISODate);
|
||||
obj["endTime"] = task.endTime.toString(Qt::ISODate);
|
||||
obj["durationMinutes"] = task.durationMinutes;
|
||||
obj["estimatedDurationMinutes"] = task.estimatedDurationMinutes;
|
||||
obj["savePath"] = task.savePath;
|
||||
obj["status"] = taskStatusToString(task.status);
|
||||
obj["HalogenLampPreheatingTime_Minute"] = task.HalogenLampPreheatingTime_Minute;
|
||||
@ -175,9 +177,10 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToTimedTask(const QJsonO
|
||||
{
|
||||
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.startTime = QDateTime::fromString(QString(), Qt::ISODate);
|
||||
task.endTime = QDateTime::fromString(QString(), Qt::ISODate);
|
||||
task.durationMinutes = json["durationMinutes"].toDouble();
|
||||
task.estimatedDurationMinutes = json["estimatedDurationMinutes"].toDouble();
|
||||
task.savePath = json["savePath"].toString();
|
||||
task.status = stringToTaskStatus(json["status"].toString());
|
||||
task.HalogenLampPreheatingTime_Minute = json["HalogenLampPreheatingTime_Minute"].toDouble();
|
||||
@ -220,6 +223,10 @@ void TaskExecutor::execute(const TimedTask& task)
|
||||
|
||||
m_task = task;
|
||||
m_task.startTime = QDateTime::currentDateTime();
|
||||
m_task.status = TaskStatus::Running;
|
||||
|
||||
emit taskUpdated(m_task);
|
||||
|
||||
|
||||
m_currentSubTaskIndex = 0;
|
||||
m_isRunning = true;
|
||||
@ -293,6 +300,7 @@ void TaskExecutor::onSequenceComplete(int status)
|
||||
qDebug() << "TaskExecutor: subtask "<< m_currentSubTaskIndex<< " time consuming(Minutes): "<< subTask.durationMinutes;
|
||||
|
||||
emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0));
|
||||
emit taskUpdated(m_task);
|
||||
}
|
||||
|
||||
//
|
||||
@ -315,6 +323,8 @@ void TaskExecutor::onSequenceComplete(int status)
|
||||
int nestSubTaskIndex = m_currentSubTaskIndex + 1;
|
||||
if (nestSubTaskIndex >= m_task.subTasks.size())
|
||||
{
|
||||
emit switchD65LampSignal(0);
|
||||
emit switchSlrSignal(0);
|
||||
emit switchHalogenLampSignal(0);
|
||||
return;
|
||||
}
|
||||
@ -501,26 +511,55 @@ void TaskScheduler::stop()
|
||||
|
||||
void TaskScheduler::checkTasks()
|
||||
{
|
||||
// 检查是否所有任务都不需要执行
|
||||
bool allTasksDone = std::all_of(m_tasks.begin(), m_tasks.end(),
|
||||
[](const TimedTask& task) {
|
||||
return task.status != TaskStatus::Waiting;
|
||||
});
|
||||
|
||||
if (allTasksDone)
|
||||
{
|
||||
std::cerr << "TaskScheduler::checkTasks,没有任务等待执行,停止调度器" << std::endl;
|
||||
stop();
|
||||
}
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
for (auto& task : m_tasks) {
|
||||
if (m_currentTaskId >= 0)//有任务正在执行
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& task : m_tasks)
|
||||
{
|
||||
if (task.status != TaskStatus::Waiting) continue;
|
||||
|
||||
// 超过计划时间1分钟以上,认为任务已过时,跳过
|
||||
if (task.scheduledTime.addSecs(60) < now) {
|
||||
// 超过计划时间threSecs,认为任务已过时,跳过
|
||||
qint64 threSecs = 30;
|
||||
if (task.scheduledTime.addSecs(threSecs) < now)
|
||||
{
|
||||
std::cerr << "TaskScheduler::checkTasks,任务已过时,跳过:" << task.id << std::endl;
|
||||
task.status = TaskStatus::Finished;
|
||||
task.status = TaskStatus::Timeout;
|
||||
for (size_t i = 0; i < task.subTaskCount(); i++)
|
||||
{
|
||||
task.subTasks[i].status = TaskStatus::Timeout;
|
||||
}
|
||||
|
||||
emit taskDataChanged(task);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (task.scheduledTime > now) continue;
|
||||
|
||||
// 到达计划时间,启动任务
|
||||
qint64 fireThreSecs = 5;
|
||||
if (task.scheduledTime.addSecs(-1*fireThreSecs) < now && task.scheduledTime.addSecs(fireThreSecs) > now)// 到达计划时间,启动任务
|
||||
{
|
||||
std::cerr << "TaskScheduler::checkTasks,到达计划时间,启动任务" << std::endl;
|
||||
executeTask(task);
|
||||
break; // 一次只执行一个任务
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TaskScheduler::onTaskFinished(bool success)
|
||||
{
|
||||
@ -561,10 +600,10 @@ void TaskScheduler::executeTask(TimedTask& task)
|
||||
{
|
||||
qDebug() << "TaskScheduler: Executing task" << task.id;
|
||||
|
||||
updateTaskStatus(task.id, TaskStatus::Running);
|
||||
//updateTaskStatus(task.id, TaskStatus::Running);
|
||||
m_currentTaskId = task.id;
|
||||
|
||||
emit taskStarted(task.id);
|
||||
//emit taskStarted(task.id);
|
||||
|
||||
// 创建任务执行器
|
||||
m_currentExecutor = new TaskExecutor(this);
|
||||
|
||||
@ -12,10 +12,12 @@
|
||||
|
||||
// 任务状态
|
||||
enum class TaskStatus {
|
||||
default, //未调度
|
||||
Waiting, // 等待
|
||||
Running, // 运行中
|
||||
Finished, // 结束
|
||||
Skiped //跳过
|
||||
Skiped, //跳过
|
||||
Timeout //超时
|
||||
};
|
||||
|
||||
// 子任务类型
|
||||
@ -49,14 +51,15 @@ struct SubTask {
|
||||
// ==================== 定时任务 ====================
|
||||
|
||||
struct TimedTask {
|
||||
int id = 0; // 任务ID
|
||||
QDateTime scheduledTime; // 计划时间
|
||||
QDateTime startTime; // 开始时间
|
||||
QDateTime endTime; // 结束时间
|
||||
double durationMinutes = 0; // 耗时(秒)
|
||||
QString savePath; // 数据保存路径
|
||||
QVector<SubTask> subTasks; // 子任务列表
|
||||
TaskStatus status = TaskStatus::Waiting; // 状态
|
||||
int id = 0;
|
||||
QDateTime scheduledTime;
|
||||
QDateTime startTime;
|
||||
QDateTime endTime;
|
||||
double durationMinutes = 0;
|
||||
double estimatedDurationMinutes = 0;
|
||||
QString savePath;
|
||||
QVector<SubTask> subTasks;
|
||||
TaskStatus status = TaskStatus::Waiting;
|
||||
double HalogenLampPreheatingTime_Minute;
|
||||
|
||||
// 计算所有子任务的预计总时间
|
||||
|
||||
@ -13,54 +13,20 @@
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QTreeView" name="taskTreeView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="delToptask_btn">
|
||||
<property name="text">
|
||||
<string>删除总计划任务</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QPushButton" name="addSubtask_btn">
|
||||
<property name="text">
|
||||
<string>添加子任务</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="addToptask_btn">
|
||||
<widget class="QLineEdit" name="taskFileSelect_lineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="taskFileSelect_btn">
|
||||
<property name="text">
|
||||
<string>添加总计划任务</string>
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QPushButton" name="delSubtask_btn">
|
||||
<property name="text">
|
||||
<string>删除子任务</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QPushButton" name="stop_btn">
|
||||
<property name="text">
|
||||
<string>停止调度</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboBox"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="refresh_btn">
|
||||
<property name="text">
|
||||
@ -68,7 +34,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="start_btn">
|
||||
<property name="text">
|
||||
<string>开始调度</string>
|
||||
@ -82,6 +48,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="stop_btn">
|
||||
<property name="text">
|
||||
<string>停止调度</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="collapseAll_btn">
|
||||
<property name="text">
|
||||
@ -89,11 +62,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@ -546,49 +546,13 @@ void TwoMotorControl::onAddRecordLine_btn()
|
||||
{
|
||||
// 准备数据:获取y马达的当前位置,获取x马达的当前位置和最大位置
|
||||
double currentPosOfYmotor = 15;
|
||||
|
||||
double currentPosOfXmotor = 0;
|
||||
double maxRangeOfXmotor = 50;
|
||||
|
||||
//获取选中行的索引
|
||||
int currentRow = ui.recordLine_tableWidget->currentRow();
|
||||
std::cout << "currentRow:" << currentRow << std::endl;
|
||||
|
||||
QTableWidgetItem* Item1 = new QTableWidgetItem(QString::number(currentPosOfYmotor, 10, 2));
|
||||
QTableWidgetItem* Item2 = new QTableWidgetItem(QString::number(1, 10, 2));
|
||||
QTableWidgetItem* Item3 = new QTableWidgetItem(QString::number(currentPosOfXmotor, 10, 2));
|
||||
QTableWidgetItem* Item4 = new QTableWidgetItem(QString::number(1, 10, 2));
|
||||
QTableWidgetItem* Item5 = new QTableWidgetItem(QString::number(maxRangeOfXmotor, 10, 2));
|
||||
QTableWidgetItem* Item6 = new QTableWidgetItem(QString::number(1, 10, 2));
|
||||
Item1->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
Item2->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
Item3->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
Item4->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
Item5->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
Item6->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
if (currentRow == -1)//当没有选中行时
|
||||
{
|
||||
int RowCount = ui.recordLine_tableWidget->rowCount();//Returns the number of rows. 从1开始的
|
||||
ui.recordLine_tableWidget->insertRow(RowCount);//增加一行,形参是从0开始的
|
||||
|
||||
ui.recordLine_tableWidget->setItem(RowCount, 0, Item1);
|
||||
ui.recordLine_tableWidget->setItem(RowCount, 1, Item2);
|
||||
ui.recordLine_tableWidget->setItem(RowCount, 2, Item3);
|
||||
ui.recordLine_tableWidget->setItem(RowCount, 3, Item4);
|
||||
ui.recordLine_tableWidget->setItem(RowCount, 4, Item5);
|
||||
ui.recordLine_tableWidget->setItem(RowCount, 5, Item6);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui.recordLine_tableWidget->insertRow(currentRow + 1);//增加一行,形参是从0开始的
|
||||
|
||||
ui.recordLine_tableWidget->setItem(currentRow + 1, 0, Item1);
|
||||
ui.recordLine_tableWidget->setItem(currentRow + 1, 1, Item2);
|
||||
ui.recordLine_tableWidget->setItem(currentRow + 1, 2, Item3);
|
||||
ui.recordLine_tableWidget->setItem(currentRow + 1, 3, Item4);
|
||||
ui.recordLine_tableWidget->setItem(currentRow + 1, 4, Item5);
|
||||
ui.recordLine_tableWidget->setItem(currentRow + 1, 5, Item6);
|
||||
}
|
||||
PathLineManager::addRecordLine(ui.recordLine_tableWidget,
|
||||
currentPosOfYmotor, 1.0,
|
||||
currentPosOfXmotor, 1.0,
|
||||
maxRangeOfXmotor, 1.0);
|
||||
}
|
||||
|
||||
void TwoMotorControl::onRemoveRecordLine_btn()
|
||||
@ -612,103 +576,37 @@ void TwoMotorControl::onSaveRecordLine2File_btn()
|
||||
// 确保采集线存在
|
||||
if (ui.recordLine_tableWidget->rowCount() <= 0)
|
||||
{
|
||||
QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请先生成轨迹!"));
|
||||
QMessageBox::information(this, QString::fromLocal8Bit("提示"),
|
||||
QString::fromLocal8Bit("请先生成轨迹!"));
|
||||
return;
|
||||
}
|
||||
|
||||
FileOperation* fileOperation = new FileOperation();
|
||||
string directory = fileOperation->getDirectoryOfExe();
|
||||
|
||||
QString RecordLineFilePath = QFileDialog::getSaveFileName(this, tr("Save RecordLine3 File"),
|
||||
QString::fromStdString(directory),
|
||||
tr("RecordLineFile3 (*.RecordLine3)"));
|
||||
|
||||
if (RecordLineFilePath.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* RecordLineFileHandle = fopen(RecordLineFilePath.toStdString().c_str(), "wb+");
|
||||
|
||||
double number = ui.recordLine_tableWidget->rowCount() * ui.recordLine_tableWidget->columnCount();
|
||||
fwrite(&number, sizeof(double), 1, RecordLineFileHandle);
|
||||
|
||||
double* data = new double[number];
|
||||
//double data[number];
|
||||
for (size_t i = 0; i < ui.recordLine_tableWidget->rowCount(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < ui.recordLine_tableWidget->columnCount(); j++)
|
||||
{
|
||||
data[i * ui.recordLine_tableWidget->columnCount() + j] = ui.recordLine_tableWidget->item(i, j)->text().toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(data, sizeof(double), number, RecordLineFileHandle);
|
||||
|
||||
fclose(RecordLineFileHandle);
|
||||
delete[] data;
|
||||
|
||||
//QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("保存成功!"));
|
||||
PathLineManager::saveToFile(RecordLineFilePath, ui.recordLine_tableWidget);
|
||||
}
|
||||
|
||||
void TwoMotorControl::onReadRecordLineFile_btn()
|
||||
{
|
||||
//打开文件
|
||||
FileOperation* fileOperation = new FileOperation();
|
||||
string directory = fileOperation->getDirectoryOfExe();
|
||||
|
||||
QString RecordLineFilePath = QFileDialog::getOpenFileName(this, tr("Open RecordLine3 File"),
|
||||
QString::fromStdString(directory),
|
||||
tr("RecordLineFile (*.RecordLine3)"));
|
||||
|
||||
if (RecordLineFilePath.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
readRecordLineFile(RecordLineFilePath);
|
||||
}
|
||||
void TwoMotorControl::readRecordLineFile(QString RecordLineFilePath)
|
||||
{
|
||||
FILE* RecordLineFileHandle = fopen(RecordLineFilePath.toStdString().c_str(), "rb");
|
||||
double number;
|
||||
|
||||
//读取数据
|
||||
fread(&number, sizeof(double), 1, RecordLineFileHandle);
|
||||
|
||||
double* data = new double[number];
|
||||
for (size_t i = 0; i < number; i++)
|
||||
{
|
||||
fread(data + i, sizeof(double), 1, RecordLineFileHandle);
|
||||
//std::cout << *(data + i) << std::endl;
|
||||
}
|
||||
|
||||
//向tableWidget添加采集线
|
||||
//(1)去掉tableWidget中所有的行
|
||||
int rowCount = ui.recordLine_tableWidget->rowCount();
|
||||
for (size_t i = 0; i < rowCount; i++)
|
||||
{
|
||||
ui.recordLine_tableWidget->removeRow(0);
|
||||
}
|
||||
//(2)添加行(采集线)
|
||||
int RecordLineCount = number / ui.recordLine_tableWidget->columnCount();
|
||||
for (size_t i = 0; i < RecordLineCount; i++)
|
||||
{
|
||||
ui.recordLine_tableWidget->insertRow(0);
|
||||
|
||||
}
|
||||
//(3)向tableWidget填充数据
|
||||
for (size_t i = 0; i < ui.recordLine_tableWidget->rowCount(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < ui.recordLine_tableWidget->columnCount(); j++)
|
||||
{
|
||||
QTableWidgetItem* tmp = new QTableWidgetItem(QString::number(data[i * ui.recordLine_tableWidget->columnCount() + j], 10, 5));
|
||||
tmp->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
ui.recordLine_tableWidget->setItem(i, j, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(RecordLineFileHandle);
|
||||
delete[] data;
|
||||
|
||||
//QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("读取成功!"));
|
||||
PathLineManager::readFromFile(RecordLineFilePath, ui.recordLine_tableWidget);
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
#include "SingleLensReflexCameraWindow.h"
|
||||
#include "DepthCameraWindow.h"
|
||||
|
||||
#include "PathLine.h"
|
||||
|
||||
#define PI 3.1415926
|
||||
|
||||
class TwoMotorControl : public QDialog, public MotorWindowBase
|
||||
|
||||
Reference in New Issue
Block a user