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

7
RoutingThread::RoutingThread(QObject *parent)
8
    : QThread(parent), _calculating(false), _stop(false), _restart(false) {
9

10 11 12 13
  static std::once_flag flag;
  std::call_once(flag,
                 [] { qRegisterMetaType<PtrRoutingData>("PtrRoutingData"); });
}
14

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

24
bool RoutingThread::calculating() const { return this->_calculating; }
25

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

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

43
void RoutingThread::run() {
44
  qWarning() << "RoutingWorker::run(): thread start.";
45 46
  while (!this->_stop) {
#ifdef DEBUG_CIRCULAR_SURVEY
47 48
    qWarning() << "RoutingWorker::run(): calculation "
                  "started.";
49
#endif
50
    // Copy input.
51
#ifdef SHOW_CIRCULAR_SURVEY_TIME
52
    auto start = std::chrono::high_resolution_clock::now();
53
#endif
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 62
    auto safeAreaENU = par.safeArea;
    auto numRuns = par.numRuns;
    auto numSolutionsPerRun = par.numSolutionsPerRun;
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
#ifdef DEBUG_CIRCULAR_SURVEY
71 72
        qWarning() << "RoutingWorker::run(): "
                      "not able to generate transects.";
73
#endif
74 75
      } else {
        // Prepare data for routing.
76 77 78 79
        auto &routeInfoVector = pRouteData->routeInfoVector;
        auto &routeVector = pRouteData->routeVector;
        snake::RouteParameter snakePar;
        snakePar.numSolutionsPerRun = numSolutionsPerRun;
80
        const auto maxRoutingTime = std::chrono::minutes(10);
81 82
        const auto routingEnd =
            std::chrono::high_resolution_clock::now() + maxRoutingTime;
83
        const auto &restart = this->_restart;
84
        snakePar.stop = [&restart, routingEnd] {
85 86 87
          bool expired = std::chrono::high_resolution_clock::now() > routingEnd;
          return restart || expired;
        };
88 89 90 91 92

        // Route transects.
        bool success = snake::route(safeAreaENU, transectsENU, routeInfoVector,
                                    routeVector, snakePar);

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