DefaultManager.cpp 9.96 KB
Newer Older
1 2 3 4 5
#include "DefaultManager.h"
#include "Wima/Geometry/GeoUtilities.h"
#include "Wima/Geometry/PolygonCalculus.h"

#include "MissionSettingsItem.h"
6 7
#include "SimpleMissionItem.h"

8

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
WaypointManager::DefaultManager::DefaultManager(Settings &settings,
                                                AreaInterface &interface)
    : ManagerBase(settings)
    , _areaInterface(&interface)
{

}

void WaypointManager::DefaultManager::clear()
{
    _dirty = true;
    _waypoints.clear();
    _currentWaypoints.clear();
    _missionItems.clearAndDeleteContents();
    _currentMissionItems.clearAndDeleteContents();
    _waypointsVariant.clear();
    _currentWaypointsVariant.clear();
}

28 29 30
bool WaypointManager::DefaultManager::update()
{
    // extract waypoints
31 32
    _currentWaypoints.clear();
    Slicer::update(_waypoints, _currentWaypoints);
33 34 35 36 37 38
    return _worker();
}

bool WaypointManager::DefaultManager::next()
{
    // extract waypoints
39 40
    _currentWaypoints.clear();
    Slicer::next(_waypoints, _currentWaypoints);
41 42 43 44 45 46
    return _worker();
}

bool WaypointManager::DefaultManager::previous()
{
    // extract waypoints
47 48
    _currentWaypoints.clear();
    Slicer::previous(_waypoints, _currentWaypoints);
49 50 51 52 53 54
    return _worker();
}

bool WaypointManager::DefaultManager::reset()
{
    // extract waypoints
55 56
    _currentWaypoints.clear();
    Slicer::reset(_waypoints, _currentWaypoints);
57 58 59
    return _worker();
}

60 61 62 63
bool WaypointManager::DefaultManager::_insertMissionItem(const QGeoCoordinate &c,
                                                         size_t index,
                                                         QmlObjectListModel &list,
                                                         bool doUpdate)
64 65 66 67 68
{
    using namespace WaypointManager::Utils;

    if ( !insertMissionItem(c,
                            index /*insertion index*/,
69
                            list,
70 71
                            _settings->vehicle(),
                            _settings->isFlyView(),
72
                            &list /*parent*/,
73 74 75
                            doUpdate /*do update*/) )
    {
        qWarning("WaypointManager::DefaultManager::next(): insertMissionItem failed.");
76
        Q_ASSERT(false);
77 78 79 80 81
        return false;
    }
    return true;
}

82 83 84 85 86 87 88
bool WaypointManager::DefaultManager::_insertMissionItem(const QGeoCoordinate &c,
                                                         size_t index,
                                                         bool doUpdate)
{
    return _insertMissionItem(c, index, _currentMissionItems, doUpdate);
}

89 90 91 92 93 94 95
bool WaypointManager::DefaultManager::_calcShortestPath(
        const QGeoCoordinate &start,
        const QGeoCoordinate &destination,
        QVector<QGeoCoordinate> &path)
{
        using namespace GeoUtilities;
        using namespace PolygonCalculus;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
96 97 98 99 100 101 102 103 104
        QPolygonF joinedArea2D;
        toCartesianList(_areaInterface->joinedArea()->coordinateList(), /*origin*/ start, joinedArea2D);
        QPointF start2D(0,0);
        QPointF end2D;
        toCartesian(destination, start, end2D);
        QVector<QPointF> path2DOut;

        bool retVal = PolygonCalculus::shortestPath(joinedArea2D, start2D, end2D, path2DOut);
        toGeoList(path2DOut, /*origin*/ start, path);
105 106 107 108 109 110 111 112

        return  retVal;
}

bool WaypointManager::DefaultManager::_worker()
{
    using namespace WaypointManager::Utils;

113
    if (_waypoints.count() < 1 || !_settings->valid()) {
114 115 116
        return false;
    }

117 118 119
    if (_dirty) {
        _missionItems.clearAndDeleteContents();
        _waypointsVariant.clear();
120
        // No initialization of _missionItems, don't need MissionSettingsItem here.
121
        for (size_t i = 0; i < size_t(_waypoints.size()); ++i) {
122
            auto &c = _waypoints.at(i);
123 124 125
            _insertMissionItem(c, _missionItems.count(), _missionItems, false /*update list*/);
            _waypointsVariant.push_back(QVariant::fromValue(c));
        }
126 127
        updateHirarchy(_missionItems);
        updateSequenceNumbers(_missionItems, 1); // Start with 1, since MissionSettingsItem missing.
128 129 130 131 132
        _dirty = false;
    }

    _currentMissionItems.clearAndDeleteContents();
    initialize(_currentMissionItems, _settings->vehicle(), _settings->isFlyView());
133

134
    // Precondition.
135 136
    if (!_settings->homePosition().isValid()){
        qWarning("WaypointManager::DefaultManager::next(): home position invalid.");
Valentin Platzgummer's avatar
Valentin Platzgummer committed
137
        Q_ASSERT(false);
138 139
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
140

141 142
    // Calculate path from home to first waypoint.
    QVector<QGeoCoordinate> arrivalPath;
143
    if ( !_calcShortestPath(_settings->homePosition(), _currentWaypoints.first(), arrivalPath) ) {
144 145 146
        qWarning("WaypointManager::DefaultManager::next(): Not able to calc path from home position to first waypoint.");
        return false;
    }
147 148 149 150
    if (!arrivalPath.empty())
        arrivalPath.removeFirst();
    if (!arrivalPath.empty())
        arrivalPath.removeLast();
151 152 153

    // calculate path from last waypoint to home
    QVector<QGeoCoordinate> returnPath;
154
    if ( !_calcShortestPath(_currentWaypoints.last(), _settings->homePosition(), returnPath) ) {
155
        qWarning("WaypointManager::DefaultManager::next(): Not able to calc path from home position to last waypoint.");
156
        return false;
157
    }
158 159 160 161
    if (!returnPath.empty())
        returnPath.removeFirst();
    if (!returnPath.empty())
        returnPath.removeLast();
162 163 164 165 166



    // Create mission items.
    // Set home position of MissionSettingsItem.
167
    MissionSettingsItem* settingsItem = _currentMissionItems.value<MissionSettingsItem *>(0);
168
    if (settingsItem == nullptr) {
169
        Q_ASSERT(false);
170 171 172 173 174
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
        return false;
    }
    settingsItem->setCoordinate(_settings->homePosition());

175
    // First mission item is takeoff command.
176 177
    _insertMissionItem(_settings->homePosition(), 1 /*insertion index*/,  false /*do update*/);
    SimpleMissionItem *takeoffItem = _currentMissionItems.value<SimpleMissionItem*>(1);
178 179
    if (takeoffItem == nullptr) {
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
180
        Q_ASSERT(takeoffItem != nullptr);
181 182
        return false;
    }
183
    makeTakeOffCmd(takeoffItem, _settings->masterController()->managerVehicle());
184 185

    // Create change speed item.
186 187
    _insertMissionItem(_settings->homePosition(), 2 /*insertion index*/, false /*do update*/);
    SimpleMissionItem *speedItem = _currentMissionItems.value<SimpleMissionItem*>(2);
188 189
    if (speedItem == nullptr) {
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
190
        Q_ASSERT(speedItem != nullptr);
191 192
        return false;
    }
193
    makeSpeedCmd(speedItem, _settings->arrivalReturnSpeed());
194 195 196

    // insert arrival path
    for (auto coordinate : arrivalPath) {
197 198
        _insertMissionItem(coordinate,
                           _currentMissionItems.count() /*insertion index*/,
199 200 201 202
                           false /*do update*/);
    }

    // Create change speed item (after arrival path).
203 204 205
    int index = _currentMissionItems.count();
    _insertMissionItem(_currentWaypoints.first(), index /*insertion index*/, false /*do update*/);
    speedItem = _currentMissionItems.value<SimpleMissionItem*>(index);
206
    if (speedItem == nullptr) {
207
        Q_ASSERT(false);
208 209 210
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
        return false;
    }
211
    makeSpeedCmd(speedItem, _settings->flightSpeed());
212 213

    // Insert slice.
214 215 216
    for (auto coordinate : _currentWaypoints) {
        _insertMissionItem(coordinate,
                           _currentMissionItems.count() /*insertion index*/,
217 218 219 220
                           false /*do update*/);
    }

    // Create change speed item, after slice.
221 222 223
    index = _currentMissionItems.count();
    _insertMissionItem(_currentWaypoints.last(), index /*insertion index*/, false /*do update*/);
    speedItem = _currentMissionItems.value<SimpleMissionItem*>(index);
224
    if (speedItem == nullptr) {
225
        Q_ASSERT(false);
226 227 228 229
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
        return false;
    }
    speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED); // set coordinate must be after setCommand (setCommand sets coordinate to zero)
230
    speedItem->setCoordinate(_currentWaypoints.last());
231 232 233 234
    speedItem->missionItem().setParam2(_settings->arrivalReturnSpeed());

    // Insert return path coordinates.
    for (auto coordinate : returnPath) {
235 236
        _insertMissionItem(coordinate,
                           _currentMissionItems.count() /*insertion index*/,
237 238 239 240
                           false /*do update*/);
    }

    // Set land command for last mission item.
241 242 243
    index = _currentMissionItems.count();
    _insertMissionItem(_settings->homePosition(), index /*insertion index*/, false /*do update*/);
    SimpleMissionItem *landItem = _currentMissionItems.value<SimpleMissionItem*>(index);
244
    if (landItem == nullptr) {
245
        Q_ASSERT(false);
246 247 248 249 250 251 252 253
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
        return false;
    }

    MAV_CMD landCmd = _settings->vehicle()->vtol() ? MAV_CMD_NAV_VTOL_LAND : MAV_CMD_NAV_LAND;
    if (_settings->vehicle()->firmwarePlugin()->supportedMissionCommands().contains(landCmd)) {
        landItem->setCommand(landCmd);
    } else {
254
        Q_ASSERT(false);
255 256 257 258 259 260
        qWarning("WaypointManager::DefaultManager::next(): Land command not supported!");
        return false;
    }

    // Prepend arrival path to slice.
    for ( long i = arrivalPath.size()-1; i >=0; --i )
261
        _currentWaypoints.push_front(arrivalPath[i]);
262 263
    // Append return path to slice.
    for ( auto c : returnPath )
264 265 266 267 268
        _currentWaypoints.push_back(c);

    _currentWaypointsVariant.clear();
    for ( auto c : _currentWaypoints)
        _currentWaypointsVariant.push_back(QVariant::fromValue(c));
269 270 271


    // Set altitude.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
272
    for (int i = 1; i < _currentMissionItems.count(); ++i) {
273
        SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
274
        if (item == nullptr) {
275
            Q_ASSERT(false);
276 277 278 279 280 281 282 283
            qWarning("WimaController::updateAltitude(): nullptr");
            return false;
        }
        item->altitude()->setRawValue(_settings->altitude());
    }

    return true;
}