#include "RTLManager.h" #include "Wima/Geometry/GeoUtilities.h" #include "Wima/Geometry/PolygonCalculus.h" #include "MissionSettingsItem.h" #include "SimpleMissionItem.h" WaypointManager::RTLManager::RTLManager(Settings &settings, AreaInterface &interface) : ManagerBase(settings), _areaInterface(&interface) {} void WaypointManager::RTLManager::setWaypoints( const QVector &waypoints) { (void)waypoints; return; } void WaypointManager::RTLManager::push_back(const QGeoCoordinate &wp) { (void)wp; return; } void WaypointManager::RTLManager::push_front(const QGeoCoordinate &wp) { (void)wp; return; } void WaypointManager::RTLManager::clear() { _dirty = true; _waypoints.clear(); _currentWaypoints.clear(); _missionItems.clearAndDeleteContents(); _currentMissionItems.clearAndDeleteContents(); _waypointsVariant.clear(); _currentWaypointsVariant.clear(); } void WaypointManager::RTLManager::insert(std::size_t i, const QGeoCoordinate &wp) { (void)i; (void)wp; return; } std::size_t WaypointManager::RTLManager::size() const { return 0; } void WaypointManager::RTLManager::remove(std::size_t i) { (void)i; } bool WaypointManager::RTLManager::update() { this->clear(); return _worker(); } bool WaypointManager::RTLManager::next() { return true; } bool WaypointManager::RTLManager::previous() { return true; } bool WaypointManager::RTLManager::reset() { return true; } bool WaypointManager::RTLManager::checkPrecondition(QString &errorString) { // Be aware of the error message order! Vehicle *managerVehicle = _settings->masterController()->managerVehicle(); if (managerVehicle->isOfflineEditingVehicle()) { errorString.append("No vehicle connected. Smart RTL not available."); return false; } if (!managerVehicle->flying()) { errorString.append("Vehicle is not flying. Smart RTL not available."); return false; } if (!_areaInterface->joinedArea()->containsCoordinate( managerVehicle->coordinate())) { errorString.append( "Vehicle not inside save area. Smart RTL not available."); return false; } return true; } bool WaypointManager::RTLManager::_insertMissionItem(const QGeoCoordinate &c, size_t index, QmlObjectListModel &list, bool doUpdate) { using namespace WaypointManager::Utils; if (!insertMissionItem(c, index /*insertion index*/, list, _settings->vehicle(), _settings->isFlyView(), &list /*parent*/, doUpdate /*do update*/)) { qWarning("WaypointManager::RTLManager::next(): insertMissionItem failed."); Q_ASSERT(false); return false; } return true; } bool WaypointManager::RTLManager::_insertMissionItem(const QGeoCoordinate &c, size_t index, bool doUpdate) { return _insertMissionItem(c, index, _currentMissionItems, doUpdate); } bool WaypointManager::RTLManager::_calcShortestPath( const QGeoCoordinate &start, const QGeoCoordinate &destination, QVector &path) { using namespace GeoUtilities; using namespace PolygonCalculus; QPolygonF joinedArea2D; toCartesianList(_areaInterface->joinedArea()->coordinateList(), /*origin*/ start, joinedArea2D); QPointF start2D(0, 0); QPointF end2D; toCartesian(destination, start, end2D); QVector path2DOut; bool retVal = PolygonCalculus::shortestPath(joinedArea2D, start2D, end2D, path2DOut); toGeoList(path2DOut, /*origin*/ start, path); return retVal; } bool WaypointManager::RTLManager::_worker() { // Precondition: settings must be valid. using namespace WaypointManager::Utils; if (!_settings->valid()) { return false; } _currentMissionItems.clearAndDeleteContents(); initialize(_currentMissionItems, _settings->vehicle(), _settings->isFlyView()); // Calculate path from vehicle to home position. QVector returnPath; auto vehicleCoordinate = _settings->masterController()->managerVehicle()->coordinate(); if (!_calcShortestPath(vehicleCoordinate, _settings->homePosition(), returnPath)) { qWarning("WaypointManager::RTLManager::next(): Not able to calc path from " "vehicle to home position."); return false; } // Create mission items. // Set home position of MissionSettingsItem. MissionSettingsItem *settingsItem = _currentMissionItems.value(0); if (settingsItem == nullptr) { Q_ASSERT(false); qWarning("WaypointManager::RTLManager::next(): nullptr."); return false; } settingsItem->setCoordinate(vehicleCoordinate); // Create change speed item. int index = _currentMissionItems.count(); _insertMissionItem(vehicleCoordinate, index /*insertion index*/, false /*do update*/); SimpleMissionItem *speedItem = _currentMissionItems.value(index); if (speedItem == nullptr) { qWarning("WaypointManager::RTLManager::next(): nullptr."); Q_ASSERT(speedItem != nullptr); return false; } makeSpeedCmd(speedItem, _settings->arrivalReturnSpeed()); // Insert return path coordinates. for (auto coordinate : returnPath) { index = _currentMissionItems.count(); _insertMissionItem(coordinate, index /*insertion index*/, false /*do update*/); } // Set land command for last mission item. index = _currentMissionItems.count(); _insertMissionItem(_settings->homePosition(), index /*insertion index*/, false /*do update*/); SimpleMissionItem *landItem = _currentMissionItems.value(index); if (landItem == nullptr) { Q_ASSERT(false); qWarning("WaypointManager::RTLManager::next(): nullptr."); return false; } makeLandCmd(landItem, _settings->masterController()->managerVehicle()); // Set altitude. for (int i = 1; i < _currentMissionItems.count(); ++i) { SimpleMissionItem *item = _currentMissionItems.value(i); if (item == nullptr) { Q_ASSERT(false); qWarning("WimaController::updateAltitude(): nullptr"); return false; } item->altitude()->setRawValue(_settings->altitude()); } // Update list _currentMissionItems. updateHirarchy(_currentMissionItems); updateSequenceNumbers(_currentMissionItems); // Append return path to _currentWaypoints. for (auto c : returnPath) _currentWaypoints.push_back(c); // Create variant list. _currentWaypointsVariant.clear(); for (auto c : _currentWaypoints) _currentWaypointsVariant.push_back(QVariant::fromValue(c)); return true; }