RoutingThread.cpp 4.07 KB
Newer Older
1
#include "RoutingThread.h"
2 3 4 5 6
// std
#include <chrono>
// Qt
#include <QDebug>

7 8 9
#include "QGCLoggingCategory.h"
QGC_LOGGING_CATEGORY(RoutingWorkerLog, "RoutingWorkerLog")

10
RoutingThread::RoutingThread(QObject *parent)
11
    : QThread(parent), _calculating(false), _stop(false), _restart(false) {
12

13 14 15 16
  static std::once_flag flag;
  std::call_once(flag,
                 [] { qRegisterMetaType<PtrRoutingData>("PtrRoutingData"); });
}
17

18
RoutingThread::~RoutingThread() {
19 20 21 22 23 24 25 26
  this->_stop = true;
  Lock lk(this->_mutex);
  this->_restart = true;
  this->_cv.notify_one();
  lk.unlock();
  this->wait();
}

27
bool RoutingThread::calculating() const { return this->_calculating; }
28

29 30
void RoutingThread::route(const RoutingParameter &par,
                          const Generator &generator) {
31 32
  // Sample input.
  Lock lk(this->_mutex);
33
  this->_par = par;
34
  this->_generator = generator;
35 36 37 38 39 40 41 42 43 44 45
  lk.unlock();

  if (!this->isRunning()) {
    this->start();
  } else {
    Lock lk(this->_mutex);
    this->_restart = true;
    this->_cv.notify_one();
  }
}

46
void RoutingThread::run() {
47
  qCWarning(RoutingWorkerLog) << "run(): thread start.";
48
  while (!this->_stop) {
49 50
    qCWarning(RoutingWorkerLog) << "run(): calculation "
                                   "started.";
51 52
    // Copy input.
    auto start = std::chrono::high_resolution_clock::now();
53

54 55 56
    this->_calculating = true;
    emit calculatingChanged();
    Lock lk(this->_mutex);
57
    auto par = this->_par;
58 59
    auto generator = this->_generator;
    lk.unlock();
60 61
    auto safeAreaENU = par.safeArea;
    auto numRuns = par.numRuns;
62
    auto numSolutionsPerRun = par.numSolutions;
63

64 65 66 67 68 69
    PtrRoutingData pRouteData(new RoutingData());
    auto &transectsENU = pRouteData->transects;
    // Generate transects.
    if (generator(transectsENU)) {
      // Check if generation was successful.
      if (transectsENU.size() == 0) {
70 71
        qCWarning(RoutingWorkerLog) << "run(): "
                                       "not able to generate transects.";
72 73
      } else {
        // Prepare data for routing.
74 75
        auto &solutionVector = pRouteData->solutionVector;

76 77
        snake::RouteParameter snakePar;
        snakePar.numSolutionsPerRun = numSolutionsPerRun;
78 79 80
        snakePar.numRuns = numRuns;

        // Set time limit to 10 min.
81
        const auto maxRoutingTime = std::chrono::minutes(10);
82 83
        const auto routingEnd =
            std::chrono::high_resolution_clock::now() + maxRoutingTime;
84
        const auto &restart = this->_restart;
85
        snakePar.stop = [&restart, routingEnd] {
86 87 88
          bool expired = std::chrono::high_resolution_clock::now() > routingEnd;
          return restart || expired;
        };
89 90

        // Route transects.
91 92
        bool success =
            snake::route(safeAreaENU, transectsENU, solutionVector, snakePar);
93

94
        // Check if routing was successful.
95
        if ((!success || solutionVector.size() < 1) && !this->_restart) {
96 97 98
          qCWarning(RoutingWorkerLog) << "run(): "
                                         "routing failed. "
                                      << snakePar.errorString.c_str();
99
        } else if (this->_restart) {
100 101
          qCWarning(RoutingWorkerLog) << "run(): "
                                         "restart requested.";
102
        } else {
103 104
          // Notify main thread.
          emit result(pRouteData);
105 106
          qCWarning(RoutingWorkerLog) << "run(): "
                                         "concurrent update success.";
107 108
        }
      }
109
    } // end calculation
110
    else {
111
      qCWarning(RoutingWorkerLog) << "run(): generator() failed.";
112
    }
113 114 115 116 117 118
    qCWarning(RoutingWorkerLog)
        << "run(): execution time: "
        << std::chrono::duration_cast<std::chrono::milliseconds>(
               std::chrono::high_resolution_clock::now() - start)
               .count()
        << " ms";
119
    // Signal calulation end and set thread to sleep.
120 121
    this->_calculating = false;
    emit calculatingChanged();
122 123 124 125 126
    Lock lk2(this->_mutex);
    if (!this->_restart) {
      this->_cv.wait(lk2, [this] { return this->_restart.load(); });
    }
    this->_restart = false;
127
  } // main loop
128
  qCWarning(RoutingWorkerLog) << "run(): thread end.";
129
}