DefaultManager.cpp 9.72 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

        return  retVal;
}

bool WaypointManager::DefaultManager::_worker()
{
111 112 113 114 115
    // Precondition:
    // _waypoints must contain valid coordinates.
    // Slicer must be called befor invoking this function.
    // E.g. Slicer::reset(_waypoints, _currentWaypoints);

116 117
    using namespace WaypointManager::Utils;

118
    if (_waypoints.count() < 1 || !_settings->valid()) {
119 120 121
        return false;
    }

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

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

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

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



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

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

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

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

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

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

    // Create change speed item, after slice.
219 220 221
    index = _currentMissionItems.count();
    _insertMissionItem(_currentWaypoints.last(), index /*insertion index*/, false /*do update*/);
    speedItem = _currentMissionItems.value<SimpleMissionItem*>(index);
222
    if (speedItem == nullptr) {
223
        Q_ASSERT(false);
224 225 226
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
        return false;
    }
227
    makeSpeedCmd(speedItem, _settings->arrivalReturnSpeed());
228 229 230

    // Insert return path coordinates.
    for (auto coordinate : returnPath) {
231 232
        _insertMissionItem(coordinate,
                           _currentMissionItems.count() /*insertion index*/,
233 234 235 236
                           false /*do update*/);
    }

    // Set land command for last mission item.
237 238 239
    index = _currentMissionItems.count();
    _insertMissionItem(_settings->homePosition(), index /*insertion index*/, false /*do update*/);
    SimpleMissionItem *landItem = _currentMissionItems.value<SimpleMissionItem*>(index);
240
    if (landItem == nullptr) {
241
        Q_ASSERT(false);
242 243 244
        qWarning("WaypointManager::DefaultManager::next(): nullptr.");
        return false;
    }
245
    makeLandCmd(landItem, _settings->masterController()->managerVehicle());
246

247 248 249 250 251 252 253 254 255
    // Set altitude.
    for (int i = 1; i < _currentMissionItems.count(); ++i) {
        SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
        if (item == nullptr) {
            Q_ASSERT(false);
            qWarning("WimaController::updateAltitude(): nullptr");
            return false;
        }
        item->altitude()->setRawValue(_settings->altitude());
256 257
    }

258 259 260 261 262
    // Update list _currentMissionItems.
    updateHirarchy(_currentMissionItems);
    updateSequenceNumbers(_currentMissionItems);


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

272
    // Create variant list.
273 274 275
    _currentWaypointsVariant.clear();
    for ( auto c : _currentWaypoints)
        _currentWaypointsVariant.push_back(QVariant::fromValue(c));
276 277 278

    return true;
}