Skip to content
RoutingThread.cpp 5.29 KiB
Newer Older
#include "RoutingThread.h"
// std
#include <chrono>
// Qt
#include <QDebug>

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 snake::FPolygon &safeArea,
                          const RoutingThread::Generator &generator) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
  // Sample input.
  Lock lk(this->_mutex);
  this->_safeArea = safeArea;
  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() {
  qWarning() << "RoutingWorker::run(): thread start.";
  while (!this->_stop) {
#ifdef DEBUG_CIRCULAR_SURVEY
    qWarning() << "RoutingWorker::run(): calculation "
                  "started.";
#ifdef SHOW_CIRCULAR_SURVEY_TIME
    auto start = std::chrono::high_resolution_clock::now();
    this->_calculating = true;
    emit calculatingChanged();
    Lock lk(this->_mutex);
    auto safeAreaENU = this->_safeArea;
    auto generator = this->_generator;
    lk.unlock();
    PtrRoutingData pRouteData(new RoutingData());
    auto &transectsENU = pRouteData->transects;
    // Generate transects.
    if (generator(transectsENU)) {
      // Check if generation was successful.
      if (transectsENU.size() == 0) {
#ifdef DEBUG_CIRCULAR_SURVEY
        qWarning() << "RoutingWorker::run(): "
                      "not able to generate transects.";
      } else {
        // Prepare data for routing.
        auto &transectsInfo = pRouteData->transectsInfo;
        auto &route = pRouteData->route;
        const auto routingStart = std::chrono::high_resolution_clock::now();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
        const auto maxRoutingTime = std::chrono::minutes(10);
        const auto routingEnd = routingStart + maxRoutingTime;
        const auto &restart = this->_restart;
        auto stopLambda = [&restart, routingEnd] {
          bool expired = std::chrono::high_resolution_clock::now() > routingEnd;
          return restart || expired;
        };
        std::string errorString;
        // Route transects
        //#ifdef SHOW_CIRCULAR_SURVEY_TIME
        //        auto s = std::chrono::high_resolution_clock::now();
        //#endif
        //        snake::route_old(safeAreaENU, transectsENU, transectsInfo,
        //        route,
        //                         stopLambda, errorString);
        //#ifdef SHOW_CIRCULAR_SURVEY_TIME
        //        qWarning() << "RoutingWorker::run(): route_old time: "
        //                   <<
        //                   std::chrono::duration_cast<std::chrono::milliseconds>(
        //                          std::chrono::high_resolution_clock::now() -
        //                          s) .count()
        //                   << " ms";
        //#endif
        //#ifdef SHOW_CIRCULAR_SURVEY_TIME
        //        s = std::chrono::high_resolution_clock::now();
        //#endif
        //        transectsInfo.clear();
        //        route.clear();
        //        errorString.clear();
        bool success = snake::route(safeAreaENU, transectsENU, transectsInfo,
                                    route, stopLambda, errorString);
        //#ifdef SHOW_CIRCULAR_SURVEY_TIME
        //        qWarning() << "RoutingWorker::run(): route time: "
        //                   <<
        //                   std::chrono::duration_cast<std::chrono::milliseconds>(
        //                          std::chrono::high_resolution_clock::now() -
        //                          s) .count()
        //                   << " ms";
        //#endif
        // Check if routing was successful.
        if ((!success || route.size() < 3) && !this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY
          qWarning() << "RoutingWorker::run(): "
                        "routing failed.";
#endif
        } else if (this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY
          qWarning() << "RoutingWorker::run(): "
                        "restart requested.";
#endif
        } else {
          // Notify main thread.
          emit result(pRouteData);
#ifdef DEBUG_CIRCULAR_SURVEY
          qWarning() << "RoutingWorker::run(): "
                        "concurrent update success.";
    } // end calculation
#ifdef DEBUG_CIRCULAR_SURVEY
    else {
      qWarning() << "RoutingWorker::run(): generator() failed.";
#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
    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
  qWarning() << "RoutingWorker::run(): thread end.";