Newer
Older
#include "Snake/QNemoHeartbeat.h"
#include <QScopedPointer>
template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value) {
return static_cast<typename std::underlying_type<T>::type>(value);
}
#define SMART_RTL_MAX_ATTEMPTS 3 // times
#define SMART_RTL_ATTEMPT_INTERVAL 200 // ms
#define EVENT_TIMER_INTERVAL 50 // ms
const char *WimaController::areaItemsName = "AreaItems";
const char *WimaController::missionItemsName = "MissionItems";
const char *WimaController::settingsGroup = "WimaController";
const char *WimaController::enableWimaControllerName = "EnableWimaController";
const char *WimaController::overlapWaypointsName = "OverlapWaypoints";
const char *WimaController::maxWaypointsPerPhaseName = "MaxWaypointsPerPhase";
const char *WimaController::startWaypointIndexName = "StartWaypointIndex";
const char *WimaController::showAllMissionItemsName = "ShowAllMissionItems";
const char *WimaController::showCurrentMissionItemsName =
"ShowCurrentMissionItems";
const char *WimaController::flightSpeedName = "FlightSpeed";
const char *WimaController::arrivalReturnSpeedName = "ArrivalReturnSpeed";
const char *WimaController::altitudeName = "Altitude";
const char *WimaController::snakeTileWidthName = "SnakeTileWidth";
const char *WimaController::snakeTileHeightName = "SnakeTileHeight";
const char *WimaController::snakeMinTileAreaName = "SnakeMinTileArea";
const char *WimaController::snakeLineDistanceName = "SnakeLineDistance";
const char *WimaController::snakeMinTransectLengthName =
"SnakeMinTransectLength";
WimaController::StatusMap WimaController::_nemoStatusMap{
std::make_pair<int, QString>(0, "No Heartbeat"),
std::make_pair<int, QString>(1, "Connected"),
std::make_pair<int, QString>(-1, "Timeout"),
std::make_pair<int, QString>(-2, "Error")};
WimaController::WimaController(QObject *parent)
: QObject(parent), _joinedArea(), _measurementArea(), _serviceArea(),
_corridor(), _localPlanDataValid(false),
_areaInterface(&_measurementArea, &_serviceArea, &_corridor,
&_joinedArea),
_WMSettings(), _defaultWM(_WMSettings, _areaInterface),
_snakeWM(_WMSettings, _areaInterface),
_rtlWM(_WMSettings, _areaInterface),
_currentWM(&_defaultWM), _WMList{&_defaultWM, &_snakeWM, &_rtlWM},
_metaDataMap(FactMetaData::createMapFromJsonFile(
QStringLiteral(":/json/WimaController.SettingsGroup.json"), this)),
_enableWimaController(settingsGroup,
_metaDataMap[enableWimaControllerName]),
_overlapWaypoints(settingsGroup, _metaDataMap[overlapWaypointsName]),
_maxWaypointsPerPhase(settingsGroup,
_metaDataMap[maxWaypointsPerPhaseName]),
_nextPhaseStartWaypointIndex(settingsGroup,
_metaDataMap[startWaypointIndexName]),
_showAllMissionItems(settingsGroup,
_metaDataMap[showAllMissionItemsName]),
_showCurrentMissionItems(settingsGroup,
_metaDataMap[showCurrentMissionItemsName]),
_flightSpeed(settingsGroup, _metaDataMap[flightSpeedName]),
_arrivalReturnSpeed(settingsGroup, _metaDataMap[arrivalReturnSpeedName]),
_altitude(settingsGroup, _metaDataMap[altitudeName]),
_snakeTileWidth(settingsGroup, _metaDataMap[snakeTileWidthName]),
_snakeTileHeight(settingsGroup, _metaDataMap[snakeTileHeightName]),
_snakeMinTileArea(settingsGroup, _metaDataMap[snakeMinTileAreaName]),
_snakeLineDistance(settingsGroup, _metaDataMap[snakeLineDistanceName]),
_snakeMinTransectLength(settingsGroup,
_metaDataMap[snakeMinTransectLengthName]),
_lowBatteryHandlingTriggered(false), _measurementPathLength(-1),
_snakeThread(this), _emptyThread(this), _currentThread(&_emptyThread),
_nemoInterface(this),
_batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) {
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
_showAllMissionItems.setRawValue(true);
_showCurrentMissionItems.setRawValue(true);
connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
&WimaController::_updateOverlap);
connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
&WimaController::_updateMaxWaypoints);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
&WimaController::_setStartIndex);
connect(&_flightSpeed, &Fact::rawValueChanged, this,
&WimaController::_updateflightSpeed);
connect(&_arrivalReturnSpeed, &Fact::rawValueChanged, this,
&WimaController::_updateArrivalReturnSpeed);
connect(&_altitude, &Fact::rawValueChanged, this,
&WimaController::_updateAltitude);
// Init waypoint managers.
bool value;
size_t overlap = _overlapWaypoints.rawValue().toUInt(&value);
Q_ASSERT(value);
size_t N = _maxWaypointsPerPhase.rawValue().toUInt(&value);
Q_ASSERT(value);
size_t startIdx = _nextPhaseStartWaypointIndex.rawValue().toUInt(&value);
Q_ASSERT(value);
(void)value;
for (auto manager : _WMList) {
manager->setOverlap(overlap);
manager->setN(N);
manager->setStartIndex(startIdx);
}
// Periodic.
connect(&_eventTimer, &QTimer::timeout, this,
&WimaController::_eventTimerHandler);
_eventTimer.start(EVENT_TIMER_INTERVAL);
// SnakeThread.
connect(_currentThread, &SnakeThread::finished, this,
&WimaController::_threadFinishedHandler);
connect(_currentThread, &SnakeThread::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
connect(this, &QObject::destroyed, &this->_snakeThread, &SnakeThread::quit);
connect(this, &QObject::destroyed, &this->_emptyThread, &SnakeThread::quit);
// NemoInterface.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_enableSnakeChangedHandler);
_enableSnakeChangedHandler();
connect(&_enableWimaController, &Fact::rawValueChanged, [this] {
if (!this->_enableWimaController.rawValue().toBool()) {
this->_enableSnake.setCookedValue(QVariant(false));
}
});
// Snake Waypoint Manager.
connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_switchToSnakeWaypointManager);
_switchToSnakeWaypointManager(_enableSnake.rawValue());
PlanMasterController *WimaController::masterController() {
}
MissionController *WimaController::missionController() {
QmlObjectListModel *WimaController::visualItems() { return &_areas; }
QmlObjectListModel *WimaController::missionItems() {
return const_cast<QmlObjectListModel *>(&_currentWM->missionItems());
}
QmlObjectListModel *WimaController::currentMissionItems() {
return const_cast<QmlObjectListModel *>(&_currentWM->currentMissionItems());
QVariantList WimaController::waypointPath() {
return const_cast<QVariantList &>(_currentWM->waypointsVariant());
QVariantList WimaController::currentWaypointPath() {
return const_cast<QVariantList &>(_currentWM->currentWaypointsVariant());
Fact *WimaController::enableWimaController() { return &_enableWimaController; }
Fact *WimaController::overlapWaypoints() { return &_overlapWaypoints; }
Fact *WimaController::maxWaypointsPerPhase() { return &_maxWaypointsPerPhase; }
Fact *WimaController::startWaypointIndex() {
return &_nextPhaseStartWaypointIndex;
Fact *WimaController::showAllMissionItems() { return &_showAllMissionItems; }
Fact *WimaController::showCurrentMissionItems() {
Fact *WimaController::flightSpeed() { return &_flightSpeed; }
Fact *WimaController::arrivalReturnSpeed() { return &_arrivalReturnSpeed; }
Fact *WimaController::altitude() { return &_altitude; }
QmlObjectListModel *WimaController::snakeTiles() {
static QmlObjectListModel list;
return &list;
}
QVariantList WimaController::snakeTileCenterPoints() {
QVector<int> WimaController::nemoProgress() {
double WimaController::phaseDistance() const {
qWarning() << "using phaseDistance dummy";
return 0.0;
double WimaController::phaseDuration() const {
qWarning() << "using phaseDuration dummy";
return 0.0;
int WimaController::nemoStatus() const {
return integral(_nemoInterface.status());
}
QString WimaController::nemoStatusString() const {
return _nemoStatusMap.at(nemoStatus());
bool WimaController::snakeCalcInProgress() const {
void WimaController::setMasterController(PlanMasterController *masterC) {
_masterController = masterC;
_WMSettings.setMasterController(masterC);
emit masterControllerChanged();
void WimaController::setMissionController(MissionController *missionC) {
_missionController = missionC;
_WMSettings.setMissionController(missionC);
emit missionControllerChanged();
void WimaController::nextPhase() { _calcNextPhase(); }
void WimaController::previousPhase() {
if (!_currentWM->previous()) {
Q_ASSERT(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
Valentin Platzgummer
committed
}
void WimaController::resetPhase() {
if (!_currentWM->reset()) {
Q_ASSERT(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
Valentin Platzgummer
committed
}
void WimaController::requestSmartRTL() {
#ifdef DEBUG_SRTL
qWarning() << "WimaController::requestSmartRTL() called";
#endif
QString errorString("Smart RTL requested.");
if (!_SRTLPrecondition(errorString)) {
qgcApp()->showMessage(errorString);
return;
}
emit smartRTLRequestConfirm();
Valentin Platzgummer
committed
}
auto &items = _currentWM->currentMissionItems();
if (_masterController && _masterController->managerVehicle() &&
items.count() > 0) {
if (!_joinedArea.containsCoordinate(
_masterController->managerVehicle()->coordinate())) {
emit forceUploadConfirm();
return false;
} else {
return forceUpload();
}
} else {
Valentin Platzgummer
committed
}
bool WimaController::forceUpload() {
auto ¤tMissionItems = _currentWM->currentMissionItems();
if (currentMissionItems.count() < 1 || !_missionController ||
!_masterController) {
qWarning() << "WimaController::forceUpload(): error:";
qWarning() << "currentMissionItems.count(): "
<< currentMissionItems.count();
qWarning() << "_missionController: " << _missionController;
qWarning() << "_masterController: " << _masterController;
} else {
_missionController->removeAll();
// Set homeposition of settingsItem.
QmlObjectListModel *visuals = _missionController->visualItems();
MissionSettingsItem *settingsItem =
visuals->value<MissionSettingsItem *>(0);
if (settingsItem == nullptr) {
Q_ASSERT(false);
qWarning("WimaController::updateCurrentMissionItems(): nullptr");
return false;
} else {
settingsItem->setCoordinate(_WMSettings.homePosition());
// Copy mission items to _missionController and send them.
for (int i = 1; i < currentMissionItems.count(); i++) {
auto *item = currentMissionItems.value<const SimpleMissionItem *>(i);
_missionController->insertSimpleMissionItem(*item, visuals->count());
}
_masterController->sendToVehicle();
return true;
}
Valentin Platzgummer
committed
void WimaController::removeFromVehicle() {
if (_masterController && _missionController) {
_masterController->removeAllFromVehicle();
_missionController->removeAll();
}
void WimaController::executeSmartRTL() {
#ifdef DEBUG_SRTL
qWarning() << "WimaController::executeSmartRTL() called";
#endif
if (_masterController && _masterController->managerVehicle()) {
forceUpload();
_masterController->managerVehicle()->startMission();
}
void WimaController::initSmartRTL() {
#ifdef DEBUG_SRTL
qWarning() << "WimaController::initSmartRTL() called";
#endif
_initSmartRTL();
}
void WimaController::removeVehicleTrajectoryHistory() {
if (_masterController && _masterController->managerVehicle()) {
_masterController->managerVehicle()
->trajectoryPoints()
->clearAndDeleteContents();
}
Valentin Platzgummer
committed
}
bool WimaController::_calcShortestPath(const QGeoCoordinate &start,
const QGeoCoordinate &destination,
QVector<QGeoCoordinate> &path) {
using namespace GeoUtilities;
using namespace PolygonCalculus;
QPolygonF polygon2D;
toCartesianList(_joinedArea.coordinateList(), /*origin*/ start, polygon2D);
QPointF start2D(0, 0);
QPointF end2D;
toCartesian(destination, start, end2D);
QVector<QPointF> path2D;
Valentin Platzgummer
committed
bool retVal =
PolygonCalculus::shortestPath(polygon2D, start2D, end2D, path2D);
toGeoList(path2D, /*origin*/ start, path);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
bool WimaController::setWimaPlanData(QSharedPointer<WimaPlanData> planData) {
// reset visual items
_areas.clear();
_defaultWM.clear();
_snakeWM.clear();
emit visualItemsChanged();
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit waypointPathChanged();
emit currentWaypointPathChanged();
Valentin Platzgummer
committed
Valentin Platzgummer
committed
QList<const WimaAreaData *> areaList = planData->areaList();
Valentin Platzgummer
committed
const int numAreas = 4; // extract only numAreas Areas, if there are more
// they are invalid and ignored
for (int i = 0; i < areaList.size(); i++) {
const WimaAreaData *areaData = areaList[i];
Valentin Platzgummer
committed
if (areaData->type() ==
WimaServiceAreaData::typeString) { // is it a service area?
_serviceArea = *qobject_cast<const WimaServiceAreaData *>(areaData);
areaCounter++;
_areas.append(&_serviceArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
if (areaData->type() ==
WimaMeasurementAreaData::typeString) { // is it a measurement area?
_measurementArea =
*qobject_cast<const WimaMeasurementAreaData *>(areaData);
areaCounter++;
_areas.append(&_measurementArea);
if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
_corridor = *qobject_cast<const WimaCorridorData *>(areaData);
areaCounter++;
//_visualItems.append(&_corridor); // not needed
if (areaData->type() ==
WimaJoinedAreaData::typeString) { // is it a corridor?
_joinedArea = *qobject_cast<const WimaJoinedAreaData *>(areaData);
areaCounter++;
_areas.append(&_joinedArea);
if (areaCounter >= numAreas)
break;
}
if (areaCounter != numAreas) {
Q_ASSERT(false);
return false;
}
Valentin Platzgummer
committed
auto tempMissionItems = planData->missionItems();
if (tempMissionItems.size() < 1) {
qWarning("WimaController: Mission items from WimaPlaner empty!");
return false;
}
for (auto *item : tempMissionItems) {
_defaultWM.push_back(item->coordinate());
}
_WMSettings.setHomePosition(QGeoCoordinate(
_serviceArea.depot().latitude(), _serviceArea.depot().longitude(), 0));
// auto tempMissionItems = planData->missionItems();
if (!_defaultWM.reset()) {
Q_ASSERT(false);
return false;
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit waypointPathChanged();
emit currentWaypointPathChanged();
// qWarning("WimaController: Mission items from WimaPlaner empty!");
// return false;
_snakeThread.setMeasurementArea(_measurementArea.coordinateList());
_snakeThread.setServiceArea(_serviceArea.coordinateList());
_snakeThread.setCorridor(_corridor.coordinateList());
_currentThread->start();
_localPlanDataValid = true;
return true;
WimaController *WimaController::thisPointer() { return this; }
bool WimaController::_calcNextPhase() {
if (!_currentWM->next()) {
Q_ASSERT(false);
return false;
}
Valentin Platzgummer
committed
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
bool WimaController::_setStartIndex() {
bool value;
_currentWM->setStartIndex(
_nextPhaseStartWaypointIndex.rawValue().toUInt(&value) - 1);
Q_ASSERT(value);
(void)value;
Valentin Platzgummer
committed
if (!_currentWM->update()) {
Q_ASSERT(false);
return false;
}
Valentin Platzgummer
committed
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
void WimaController::_recalcCurrentPhase() {
if (!_currentWM->update()) {
Q_ASSERT(false);
}
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
void WimaController::_updateOverlap() {
bool value;
_currentWM->setOverlap(_overlapWaypoints.rawValue().toUInt(&value));
Q_ASSERT(value);
(void)value;
if (!_currentWM->update()) {
assert(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
void WimaController::_updateMaxWaypoints() {
bool value;
_currentWM->setN(_maxWaypointsPerPhase.rawValue().toUInt(&value));
Q_ASSERT(value);
(void)value;
if (!_currentWM->update()) {
Q_ASSERT(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
void WimaController::_updateflightSpeed() {
bool value;
_WMSettings.setFlightSpeed(_flightSpeed.rawValue().toDouble(&value));
Q_ASSERT(value);
(void)value;
if (!_currentWM->update()) {
Q_ASSERT(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
void WimaController::_updateArrivalReturnSpeed() {
bool value;
_WMSettings.setArrivalReturnSpeed(
_arrivalReturnSpeed.rawValue().toDouble(&value));
Q_ASSERT(value);
(void)value;
if (!_currentWM->update()) {
Q_ASSERT(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
void WimaController::_updateAltitude() {
bool value;
_WMSettings.setAltitude(_altitude.rawValue().toDouble(&value));
Q_ASSERT(value);
(void)value;
if (!_currentWM->update()) {
Q_ASSERT(false);
}
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
void WimaController::_checkBatteryLevel() {
if (_missionController && _masterController &&
_masterController->managerVehicle()) {
Vehicle *managerVehicle = masterController()->managerVehicle();
WimaSettings *wimaSettings =
qgcApp()->toolbox()->settingsManager()->wimaSettings();
int threshold = wimaSettings->lowBatteryThreshold()->rawValue().toInt();
bool enabled = _enableWimaController.rawValue().toBool();
unsigned int minTime =
wimaSettings->minimalRemainingMissionTime()->rawValue().toUInt();
if (enabled) {
Fact *battery1percentRemaining =
managerVehicle->battery1FactGroup()->getFact(
VehicleBatteryFactGroup::_percentRemainingFactName);
Fact *battery2percentRemaining =
managerVehicle->battery2FactGroup()->getFact(
VehicleBatteryFactGroup::_percentRemainingFactName);
if (battery1percentRemaining->rawValue().toDouble() < threshold &&
battery2percentRemaining->rawValue().toDouble() < threshold) {
if (!_lowBatteryHandlingTriggered) {
_lowBatteryHandlingTriggered = true;
if (!(_missionController->remainingTime() <= minTime)) {
requestSmartRTL();
}
} else {
_lowBatteryHandlingTriggered = false;
void WimaController::_eventTimerHandler() {
// Battery level check necessary?
Fact *enableLowBatteryHandling = qgcApp()
->toolbox()
->settingsManager()
->wimaSettings()
->enableLowBatteryHandling();
if (enableLowBatteryHandling->rawValue().toBool() &&
_batteryLevelTicker.ready())
_checkBatteryLevel();
void WimaController::_smartRTLCleanUp(bool flying) {
if (!flying && _missionController) { // vehicle has landed
_switchWaypointManager(_defaultWM);
_missionController->removeAll();
disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged,
this, &WimaController::_smartRTLCleanUp);
}
void WimaController::_setPhaseDistance(double distance) {
(void)distance;
// if (!qFuzzyCompare(distance, _phaseDistance)) {
// _phaseDistance = distance;
// emit phaseDistanceChanged();
// }
void WimaController::_setPhaseDuration(double duration) {
(void)duration;
// if (!qFuzzyCompare(duration, _phaseDuration)) {
// _phaseDuration = duration;
// emit phaseDurationChanged();
// }
bool WimaController::_SRTLPrecondition(QString &errorString) {
if (!_localPlanDataValid) {
errorString.append(tr("No WiMA data available. Please define at least a "
"measurement and a service area."));
return false;
}
return _rtlWM.checkPrecondition(errorString);
void WimaController::_switchWaypointManager(
WaypointManager::ManagerBase &manager) {
if (_currentWM != &manager) {
_currentWM = &manager;
disconnect(&_overlapWaypoints, &Fact::rawValueChanged, this,
&WimaController::_updateOverlap);
disconnect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
&WimaController::_updateMaxWaypoints);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
&WimaController::_setStartIndex);
_maxWaypointsPerPhase.setRawValue(_currentWM->N());
_overlapWaypoints.setRawValue(_currentWM->overlap());
_nextPhaseStartWaypointIndex.setRawValue(_currentWM->startIndex());
connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
&WimaController::_updateOverlap);
connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
&WimaController::_updateMaxWaypoints);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
&WimaController::_setStartIndex);
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit waypointPathChanged();
qWarning() << "WimaController::_switchWaypointManager: statistics update "
"missing.";
}
}
void WimaController::_initSmartRTL() {
static int attemptCounter = 0;
attemptCounter++;
QString errorString;
if (_SRTLPrecondition(errorString)) {
if (_missionController && _masterController &&
_masterController->managerVehicle()) {
_masterController->managerVehicle()->pauseVehicle();
connect(_masterController->managerVehicle(), &Vehicle::flyingChanged,
this, &WimaController::_smartRTLCleanUp);
if (_rtlWM.update()) { // Calculate return path.
_switchWaypointManager(_rtlWM);
removeFromVehicle();
attemptCounter = 0;
emit smartRTLPathConfirm();
}
}
} else if (attemptCounter > SMART_RTL_MAX_ATTEMPTS) {
errorString.append(
tr("Smart RTL: No success after maximum number of attempts."));
qgcApp()->showMessage(errorString);
attemptCounter = 0;
} else {
_smartRTLTimer.singleShot(SMART_RTL_ATTEMPT_INTERVAL, this,
&WimaController::_initSmartRTL);
}
}
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now();
#endif
if (!_snakeThread.errorMessage().isEmpty()) {
qDebug() << _snakeThread.errorMessage();
if (_snakeThread.tilesUpdated()) {
this->tiles.clearAndDeleteContents();
auto tls = _snakeThread.tiles().polygons();
for (const auto &t : tls) {
this->tiles.append(new SnakeTile(t, &tiles));
}
emit snakeTilesChanged();
emit snakeTileCenterPointsChanged();
_nemoInterface.setTilesENU(_snakeThread.tilesENU());
_nemoInterface.setENUOrigin(_snakeThread.ENUOrigin());
#ifdef SNAKE_SHOW_TIME
auto end = std::chrono::high_resolution_clock::now();
std::cout << "WimaController::_threadFinishedHandler(): tiles: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< " ms" << std::endl;
start = std::chrono::high_resolution_clock::now();
#endif
if (_snakeThread.progressUpdated()) {
emit nemoProgressChanged();
#ifdef SNAKE_SHOW_TIME
end = std::chrono::high_resolution_clock::now();
std::cout << "WimaController::_threadFinishedHandler(): progress: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< " ms" << std::endl;
start = std::chrono::high_resolution_clock::now();
#endif
if (_snakeThread.waypointsUpdated()) {
// Copy waypoints to waypoint manager.
_snakeWM.clear();
auto waypoints = _snakeThread.waypoints();
if (waypoints.size() < 1) {
return;
}
for (auto &vertex : waypoints) {
_snakeWM.push_back(vertex);
}
// Do update.
this->_snakeWM.update(); // this can take a while (ca. 200ms)
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
emit waypointPathChanged();
}
#ifdef SNAKE_SHOW_TIME
end = std::chrono::high_resolution_clock::now();
std::cout << "WimaController::_threadFinishedHandler(): waypoints: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< " ms" << std::endl;
#endif
}
void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
if (variant.value<bool>()) {
_switchWaypointManager(_snakeWM);
} else {
_switchWaypointManager(_defaultWM);
}
}
void WimaController::_switchThreadObject(SnakeThread &thread) {
if (_currentThread != &thread) {
// SnakeThread.
disconnect(_currentThread, &SnakeThread::finished, this,
&WimaController::_threadFinishedHandler);
disconnect(_currentThread, &SnakeThread::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
// NemoInterface.
disconnect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
disconnect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
disconnect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
// SnakeThread.
connect(_currentThread, &SnakeThread::finished, this,
&WimaController::_threadFinishedHandler);
connect(_currentThread, &SnakeThread::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
// NemoInterface.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged);
connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged);
emit snakeCalcInProgressChanged();
emit snakeTilesChanged();
emit snakeTileCenterPointsChanged();
emit nemoProgressChanged();
emit nemoStatusChanged();
emit nemoStatusStringChanged();
}
void WimaController::_progressChangedHandler() {
this->_snakeThread.setProgress(this->_nemoInterface.progress());
this->_snakeThread.start();
}
void WimaController::_enableSnakeChangedHandler() {
if (this->_enableSnake.rawValue().toBool()) {
_switchThreadObject(this->_snakeThread);
this->_nemoInterface.start();
this->_snakeThread.start();
this->_nemoInterface.stop();
this->_snakeThread.quit();
_switchThreadObject(_emptyThread);