Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "RoutingThread.h"
// std
#include <chrono>
// Qt
#include <QDebug>
#include "QGCLoggingCategory.h"
QGC_LOGGING_CATEGORY(RoutingThreadLog, "RoutingThreadLog")
RoutingThread::RoutingThread(QObject *parent)
: QThread(parent), _calculating(false), _stop(false), _restart(false) {
static std::once_flag flag;
std::call_once(flag,
[] { qRegisterMetaType<PtrRoutingData>("PtrRoutingData"); });
}
RoutingThread::~RoutingThread() {
this->_stop = true;
Lock lk(this->_mutex);
this->_restart = true;
this->_cv.notify_one();
lk.unlock();
this->wait();
}
bool RoutingThread::calculating() const { return this->_calculating; }
void RoutingThread::route(const RoutingParameter &par,
const Generator &generator) {
// Sample input.
Lock lk(this->_mutex);
this->_par = par;
this->_generator = generator;
lk.unlock();
if (!this->isRunning()) {
this->start();
} else {
Lock lk(this->_mutex);
this->_restart = true;
this->_cv.notify_one();
}
}
void RoutingThread::run() {
qCDebug(RoutingThreadLog) << "run(): thread start.";
while (!this->_stop) {
qCDebug(RoutingThreadLog) << "run(): calculation "
"started.";
// Copy input.
auto start = std::chrono::high_resolution_clock::now();
this->_calculating = true;
emit calculatingChanged();
Lock lk(this->_mutex);
auto par = this->_par;
auto generator = this->_generator;
lk.unlock();
auto safeAreaENU = par.safeArea;
auto numRuns = par.numRuns;
auto numSolutionsPerRun = par.numSolutions;
PtrRoutingData pRouteData(new RoutingData());
auto &transectsENU = pRouteData->transects;
// Generate transects.
if (generator(transectsENU)) {
// Check if generation was successful.
if (transectsENU.size() == 0) {
qCDebug(RoutingThreadLog) << "run(): "
"not able to generate transects.";
} else {
// Prepare data for routing.
auto &solutionVector = pRouteData->solutionVector;
snake::RouteParameter snakePar;
snakePar.numSolutionsPerRun = numSolutionsPerRun;
snakePar.numRuns = numRuns;
// Set time limit to 10 min.
const auto maxRoutingTime = std::chrono::minutes(10);
const auto routingEnd =
std::chrono::high_resolution_clock::now() + maxRoutingTime;
const auto &restart = this->_restart;
snakePar.stop = [&restart, routingEnd] {
bool expired = std::chrono::high_resolution_clock::now() > routingEnd;
return restart || expired;
};
// Route transects.
bool success =
snake::route(safeAreaENU, transectsENU, solutionVector, snakePar);
// Check if routing was successful.
if ((!success || solutionVector.size() < 1) && !this->_restart) {
qCDebug(RoutingThreadLog) << "run(): "
"routing failed. "
<< snakePar.errorString.c_str();
} else if (this->_restart) {
qCDebug(RoutingThreadLog) << "run(): "
"restart requested.";
} else {
// Notify main thread.
emit result(pRouteData);
qCDebug(RoutingThreadLog) << "run(): "
"concurrent update success.";
}
}
} // end calculation
else {
qCDebug(RoutingThreadLog) << "run(): generator() failed.";
}
qCDebug(RoutingThreadLog)
<< "run(): execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
// Signal calulation end and set thread to sleep.
this->_calculating = false;
emit calculatingChanged();
Lock lk2(this->_mutex);
if (!this->_restart) {
this->_cv.wait(lk2, [this] { return this->_restart.load(); });
}
this->_restart = false;
} // main loop
qCDebug(RoutingThreadLog) << "run(): thread end.";
}