30#include <QtCore/QJsonArray>
31#include <QtCore/QJsonDocument>
34#define UPDATE_TIMEOUT 5000
40 , _controllerVehicle (masterController->controllerVehicle())
41 , _managerVehicle (masterController->managerVehicle())
42 , _missionManager (masterController->managerVehicle()->missionManager())
47 _resetMissionFlightStatus();
49 _updateTimer.setSingleShot(
true);
51 connect(&_updateTimer, &QTimer::timeout,
this, &MissionController::_updateTimeout);
52 connect(_planViewSettings->takeoffItemNotRequired(), &
Fact::rawValueChanged,
this, &MissionController::_recalcPlanViewState);
72void MissionController::_resetMissionFlightStatus(
void)
74 _flightStatusCalc.
reset(_controllerVehicle, _managerVehicle, _missionContainsVTOLTakeoff);
75 _missionFlightStatus = _flightStatusCalc.
status();
90 qCDebug(MissionControllerLog) <<
"start flyView" << flyView;
92 _managerVehicleChanged(_managerVehicle);
99void MissionController::_init(
void)
102 _addMissionSettings(_visualItems);
107 _initAllVisualItems();
111void MissionController::_newMissionItemsAvailableFromVehicle(
bool removeAllRequested)
113 qCDebug(MissionControllerLog) <<
"_newMissionItemsAvailableFromVehicle flyView:count" <<
_flyView << _missionManager->
missionItems().count();
127 _setupNewVisualItems();
129 const QList<MissionItem*>& newMissionItems = _missionManager->
missionItems();
130 qCDebug(MissionControllerLog) <<
"loading from vehicle: count"<< newMissionItems.count();
136 if (fakeHomeItem->
coordinate().latitude() != 0 || fakeHomeItem->
coordinate().longitude() != 0) {
142 bool weHaveItemsFromVehicle =
false;
143 for (; i < newMissionItems.count(); i++) {
144 weHaveItemsFromVehicle =
true;
145 const MissionItem* missionItem = newMissionItems[i];
151 simpleItem->deleteLater();
152 simpleItem = _takeoffMissionItem;
154 _visualItems->
append(simpleItem);
162 _initAllVisualItems();
168 _itemsRequested =
false;
174 qCCritical(MissionControllerLog) <<
"MissionControllerLog::loadFromVehicle called while offline";
176 qCCritical(MissionControllerLog) <<
"MissionControllerLog::loadFromVehicle called while syncInProgress";
178 _itemsRequested =
true;
186 qCCritical(MissionControllerLog) <<
"MissionControllerLog::sendToVehicle called while offline";
188 qCCritical(MissionControllerLog) <<
"MissionControllerLog::sendToVehicle called while syncInProgress";
190 qCDebug(MissionControllerLog) <<
"MissionControllerLog::sendToVehicle";
191 if (_visualItems->
count() == 1) {
205bool MissionController::_convertToMissionItems(
QmlObjectListModel* visualMissionItems, QList<MissionItem*>& rgMissionItems, QObject* missionItemParent)
207 if (visualMissionItems->
count() == 0) {
211 bool endActionSet =
false;
214 for (
int i=0; i<visualMissionItems->
count(); i++) {
220 qCDebug(MissionControllerLog) <<
"_convertToMissionItems seqNum:lastSeqNum:command"
229 endActionSet = settingsItem->
addMissionEndAction(rgMissionItems, lastSeqNum + 1, missionItemParent);
237 QObject* deleteParent =
new QObject();
238 QList<MissionItem*> rgMissionItems;
240 _convertToMissionItems(_visualItems, rgMissionItems, deleteParent);
241 planKML.
addMission(_controllerVehicle, _visualItems, rgMissionItems);
242 deleteParent->deleteLater();
248 QList<MissionItem*> rgMissionItems;
250 _convertToMissionItems(visualMissionItems, rgMissionItems, vehicle);
257int MissionController::_nextSequenceNumber(
void)
259 if (_visualItems->
count() == 0) {
260 qWarning() <<
"Internal error: Empty visual item list";
268VisualMissionItem* MissionController::_insertSimpleMissionItemWorker(QGeoCoordinate coordinate, MAV_CMD command,
int visualItemIndex,
bool makeCurrentItem)
270 int sequenceNumber = _nextSequenceNumber();
275 _initVisualItem(newItem);
282 if (_findPreviousAltitude(visualItemIndex, &prevAltitude, &prevAltFrame)) {
291 if (visualItemIndex == -1) {
292 _visualItems->
append(newItem);
294 _visualItems->
insert(visualItemIndex, newItem);
298 _recalcAllWithCoordinate(coordinate);
300 if (makeCurrentItem) {
312 return _insertSimpleMissionItemWorker(coordinate, MAV_CMD_NAV_WAYPOINT, visualItemIndex, makeCurrentItem);
317 int sequenceNumber = _nextSequenceNumber();
320 _initVisualItem(_takeoffMissionItem);
326 if (_findPreviousAltitude(visualItemIndex, &prevAltitude, &prevAltFrame)) {
331 if (visualItemIndex == -1) {
332 _visualItems->
append(_takeoffMissionItem);
334 _visualItems->
insert(visualItemIndex, _takeoffMissionItem);
339 if (makeCurrentItem) {
345 return _takeoffMissionItem;
351 return _planViewSettings->allowMultipleLandingPatterns()
352 ->rawValue().toBool() &&
361 }
else if (_controllerVehicle->
vtol()) {
365 return _insertSimpleMissionItemWorker(coordinate, _controllerVehicle->
vtol() ? MAV_CMD_NAV_VTOL_LAND : MAV_CMD_NAV_RETURN_TO_LAUNCH, visualItemIndex, makeCurrentItem);
371 SimpleMissionItem* simpleItem = qobject_cast<SimpleMissionItem*>(_insertSimpleMissionItemWorker(coordinate, MAV_CMD_DO_SET_ROI_LOCATION, visualItemIndex, makeCurrentItem));
382 SimpleMissionItem* simpleItem = qobject_cast<SimpleMissionItem*>(_insertSimpleMissionItemWorker(QGeoCoordinate(), MAV_CMD_DO_SET_ROI_NONE, visualItemIndex, makeCurrentItem));
402 if (_findPreviousAltitude(visualItemIndex, &prevAltitude, &prevAltFrame)) {
407 _insertComplexMissionItemWorker(mapCenterCoordinate, newItem, visualItemIndex, makeCurrentItem);
419 _insertComplexMissionItemWorker(QGeoCoordinate(), newItem, visualItemIndex, makeCurrentItem);
424void MissionController::_insertComplexMissionItemWorker(
const QGeoCoordinate& mapCenterCoordinate,
ComplexMissionItem* complexItem,
int visualItemIndex,
bool makeCurrentItem)
426 int sequenceNumber = _nextSequenceNumber();
427 bool surveyStyleItem = qobject_cast<SurveyComplexItem*>(complexItem) ||
428 qobject_cast<CorridorScanComplexItem*>(complexItem) ||
429 qobject_cast<StructureScanComplexItem*>(complexItem);
431 if (surveyStyleItem) {
432 bool rollSupported =
false;
433 bool pitchSupported =
false;
434 bool yawSupported =
false;
442 if (cameraSection->cameraModeSupported() && !cameraSection->specifyCameraMode()) {
444 cameraSection->cameraMode()->setRawValue(CAMERA_MODE_IMAGE_SURVEY);
448 if (_controllerVehicle->
firmwarePlugin()->
hasGimbal(_controllerVehicle, rollSupported, pitchSupported, yawSupported) && pitchSupported) {
450 if (!cameraSection->specifyGimbal()) {
451 cameraSection->setSpecifyGimbal(
true);
452 cameraSection->gimbalPitch()->setRawValue(-90.0);
458 if (!qobject_cast<VTOLLandingComplexItem*>(complexItem)) {
461 _initVisualItem(complexItem);
463 if (visualItemIndex == -1) {
464 _visualItems->
append(complexItem);
466 _visualItems->
insert(visualItemIndex, complexItem);
473 _recalcAllWithCoordinate(mapCenterCoordinate);
475 if (makeCurrentItem) {
483 return _visualItems ? _visualItems->
indexOf(
object) : -1;
488 if (viIndex <= 0 || viIndex >= _visualItems->
count()) {
489 qWarning() <<
"MissionController::removeVisualItem called with bad index - count:index" << _visualItems->
count() << viIndex;
496 if (item == _takeoffMissionItem) {
497 _takeoffMissionItem =
nullptr;
500 _deinitVisualItem(item);
503 if (removeSurveyStyle) {
505 bool foundSurvey =
false;
506 for (
int i=1; i<_visualItems->
count(); i++) {
515 bool rollSupported =
false;
516 bool pitchSupported =
false;
517 bool yawSupported =
false;
519 if (_controllerVehicle->
firmwarePlugin()->
hasGimbal(_controllerVehicle, rollSupported, pitchSupported, yawSupported) && pitchSupported) {
534 if (viIndex >= _visualItems->
count()) {
535 newVIIndex = _visualItems->
count() - 1;
537 newVIIndex = viIndex;
543 if (_visualItems->
count() == 1) {
553 _deinitAllVisualItems();
557 QTimer::singleShot(1000, oldItems, [oldItems] {
559 oldItems->deleteLater();
563 _settingsItem =
nullptr;
564 _takeoffMissionItem =
nullptr;
567 _visualItems = newItems;
568 if (_visualItems->
count() == 0) {
569 _addMissionSettings(_visualItems);
575 _addMissionSettings(_visualItems);
581 _setupNewVisualItems();
582 _initAllVisualItems();
584 _resetMissionFlightStatus();
591 QList<JsonParsing::KeyValidateInfo> rootKeyInfoList = {
592 { _jsonPlannedHomePositionKey, QJsonValue::Array,
true },
593 { _jsonItemsKey, QJsonValue::Array,
true },
594 { _jsonFirmwareTypeKey, QJsonValue::Double,
true },
595 { _jsonVehicleTypeKey, QJsonValue::Double,
false },
596 { _jsonCruiseSpeedKey, QJsonValue::Double,
false },
597 { _jsonHoverSpeedKey, QJsonValue::Double,
false },
598 { _jsonGlobalPlanAltitudeModeKey, QJsonValue::Double,
false },
606 qCDebug(MissionControllerLog) <<
"MissionController::_loadJsonMissionFileV2 itemCount:" << json[_jsonItemsKey].toArray().count();
611 MAV_AUTOPILOT planFileFirmwareType =
static_cast<MAV_AUTOPILOT
>(json[_jsonFirmwareTypeKey].toInt());
613 if (json.contains(_jsonVehicleTypeKey)) {
614 planFileVehicleType =
static_cast<MAV_TYPE
>(json[_jsonVehicleTypeKey].toInt());
619 appSettings->offlineEditingFirmwareClass()->setRawValue(
QGCMAVLink::firmwareClass(
static_cast<MAV_AUTOPILOT
>(json[_jsonFirmwareTypeKey].toInt())));
620 if (json.contains(_jsonVehicleTypeKey)) {
630 if (json.contains(_jsonCruiseSpeedKey)) {
631 appSettings->offlineEditingCruiseSpeed()->setRawValue(json[_jsonCruiseSpeedKey].toDouble());
633 if (json.contains(_jsonHoverSpeedKey)) {
634 appSettings->offlineEditingHoverSpeed()->setRawValue(json[_jsonHoverSpeedKey].toDouble());
636 if (json.contains(_jsonGlobalPlanAltitudeModeKey)) {
637 setGlobalAltitudeFrame(json[_jsonGlobalPlanAltitudeModeKey].toVariant().value<QGroundControlQmlGlobal::AltitudeFrame>());
640 QGeoCoordinate homeCoordinate;
647 qCDebug(MissionControllerLog) <<
"plannedHomePosition" << homeCoordinate;
651 int nextSequenceNumber = 1;
652 const QJsonArray rgMissionItems(json[_jsonItemsKey].toArray());
653 for (
int i=0; i<rgMissionItems.count(); i++) {
655 const QJsonValue& itemValue = rgMissionItems[i];
656 if (!itemValue.isObject()) {
657 errorString = tr(
"Mission item %1 is not an object").arg(i);
660 const QJsonObject itemObject = itemValue.toObject();
664 QList<JsonParsing::KeyValidateInfo> itemKeyInfoList = {
679 simpleItem->deleteLater();
680 simpleItem = takeoffItem;
682 qCDebug(MissionControllerLog) <<
"Loading simple item: nextSequenceNumber:command" << nextSequenceNumber << simpleItem->
command();
689 QList<JsonParsing::KeyValidateInfo> complexItemKeyInfoList = {
697 qCDebug(MissionControllerLog) <<
"Loading complex item type:" << complexItemType <<
"nextSequenceNumber:" << nextSequenceNumber;
700 errorString = tr(
"Unsupported complex item type: %1").arg(complexItemType);
703 if (!complexItem->
load(itemObject, nextSequenceNumber++,
errorString)) {
708 qCDebug(MissionControllerLog) <<
"Complex item load complete nextSequenceNumber:" << nextSequenceNumber;
711 errorString = tr(
"Unknown item type: %1").arg(itemType);
720 if (doJumpItem->
command() == MAV_CMD_DO_JUMP) {
734 errorString = tr(
"Could not find doJumpId: %1").arg(findDoJumpId);
746 bool firstItem =
true;
747 bool plannedHomePositionInFile =
false;
749 QString firstLine = stream.readLine();
750 const QStringList& version = firstLine.split(
" ");
752 bool versionOk =
false;
753 if (version.size() == 3 && version[0] ==
"QGC" && version[1] ==
"WPL") {
754 if (version[2] ==
"110") {
757 plannedHomePositionInFile =
true;
758 }
else if (version[2] ==
"120") {
761 plannedHomePositionInFile =
false;
768 while (!stream.atEnd()) {
770 if (item->
load(stream)) {
771 if (firstItem && plannedHomePositionInFile) {
784 errorString = tr(
"The mission file is corrupted.");
789 errorString = tr(
"The mission file is not compatible with this version of %1.").arg(QCoreApplication::applicationName());
793 if (!plannedHomePositionInFile) {
797 if (item && item->
command() == MAV_CMD_DO_JUMP) {
808 _setupNewVisualItems(loadedVisualItems);
812 _initAllVisualItems();
814 if (_visualItems->
count() > 1) {
824 QString errorMessage = tr(
"Mission: %1");
827 if (!_loadJsonMissionFileV2(json, loadedVisualItems, errorStr)) {
831 _initLoadedVisualItems(loadedVisualItems);
839 QString errorMessage = tr(
"Mission: %1");
840 QByteArray bytes = file.readAll();
841 QTextStream stream(bytes);
846 if (!_loadTextMissionFile(stream, loadedVisualItems, errorStr)) {
851 _initLoadedVisualItems(loadedVisualItems);
858 for (
int i=0; i<_visualItems->
count(); i++) {
876 qWarning() <<
"First item is not MissionSettingsItem";
879 QJsonValue coordinateValue;
881 json[_jsonPlannedHomePositionKey] = coordinateValue;
882 json[_jsonFirmwareTypeKey] = _controllerVehicle->
firmwareType();
883 json[_jsonVehicleTypeKey] = _controllerVehicle->
vehicleType();
886 json[_jsonGlobalPlanAltitudeModeKey] = _globalAltFrame;
890 QJsonArray rgJsonMissionItems;
891 for (
int i=0; i<_visualItems->
count(); i++) {
894 visualItem->
save(rgJsonMissionItems);
899 QList<MissionItem*> rgMissionItems;
901 if (_convertToMissionItems(_visualItems, rgMissionItems,
this )) {
902 QJsonObject saveObject;
903 MissionItem* missionItem = rgMissionItems[rgMissionItems.count() - 1];
904 missionItem->
save(saveObject);
905 rgJsonMissionItems.append(saveObject);
907 for (
int i=0; i<rgMissionItems.count(); i++) {
908 rgMissionItems[i]->deleteLater();
912 json[_jsonItemsKey] = rgJsonMissionItems;
919 bool takeoffStraightUp = pair.second->isTakeoffItem() && !_controllerVehicle->
fixedWing();
921 QGeoCoordinate coord1 = pair.first->exitCoordinate();
922 QGeoCoordinate coord2 = pair.second->entryCoordinate();
923 double coord2AMSLAlt = pair.second->amslEntryAlt();
924 double coord1AMSLAlt = takeoffStraightUp ? coord2AMSLAlt : pair.first->amslExitAlt();
927 if (pair.second->isTakeoffItem()) {
929 }
else if (pair.second->isLandCommand()) {
935 if (takeoffStraightUp) {
962 _flightPathSegmentHashTable[pair] = segment = prevItemPairHashTable.take(pair);
964 segment = _createFlightPathSegmentWorker(pair, mavlinkTerrainFrame);
965 _flightPathSegmentHashTable[pair] = segment;
968 _simpleFlightPathSegments.
append(segment);
973void MissionController::_recalcFlightPathSegments(
void)
976 int segmentCount = 0;
977 bool firstCoordinateNotFound =
true;
979 bool linkEndToHome =
false;
980 bool linkStartToHome = _controllerVehicle->
rover() ? true :
false;
981 bool foundRTL =
false;
982 bool homePositionValid = _settingsItem->
coordinate().isValid();
983 bool roiActive =
false;
984 bool previousItemIsIncomplete =
false;
985 bool signalSplitSegmentChanged =
false;
987 qCDebug(MissionControllerLog) <<
"_recalcFlightPathSegments homePositionValid" << homePositionValid;
991 _missionContainsVTOLTakeoff =
false;
992 _flightPathSegmentHashTable.clear();
997 _simpleFlightPathSegments.
clear();
998 _directionArrows.
clear();
1005 for (
int i=1; i<_visualItems->
count(); i++) {
1006 qobject_cast<VisualMissionItem*>(_visualItems->
get(i))->clearSimpleFlighPathSegment();
1010 for (
int i=1; i<_visualItems->
count(); i++) {
1019 if (_isROICancelItem(simpleItem)) {
1023 if (_isROIBeginItem(simpleItem)) {
1030 case MAV_CMD_NAV_TAKEOFF:
1031 case MAV_CMD_NAV_VTOL_TAKEOFF:
1032 _missionContainsVTOLTakeoff = command == MAV_CMD_NAV_VTOL_TAKEOFF;
1033 if (!linkEndToHome) {
1036 if (firstCoordinateNotFound) {
1037 linkStartToHome =
true;
1041 case MAV_CMD_NAV_RETURN_TO_LAUNCH:
1042 linkEndToHome =
true;
1057 lastFlyThroughVI = visualItem;
1067 previousItemIsIncomplete =
true;
1068 }
else if (previousItemIsIncomplete) {
1070 previousItemIsIncomplete =
false;
1071 firstCoordinateNotFound =
false;
1072 lastFlyThroughVI = visualItem;
1074 if (lastFlyThroughVI != _settingsItem || (homePositionValid && linkStartToHome)) {
1075 bool addDirectionArrow =
false;
1081 addDirectionArrow =
true;
1082 }
else if (segmentCount > 5) {
1084 addDirectionArrow =
true;
1089 lastSegmentVisualItemPair =
VisualItemPair(lastFlyThroughVI, visualItem);
1090 SimpleMissionItem* lastSimpleItem = qobject_cast<SimpleMissionItem*>(lastFlyThroughVI);
1091 bool mavlinkTerrainFrame = lastSimpleItem ? lastSimpleItem->
missionItem().
frame() == MAV_FRAME_GLOBAL_TERRAIN_ALT :
false;
1092 FlightPathSegment* segment = _addFlightPathSegment(oldSegmentTable, lastSegmentVisualItemPair, mavlinkTerrainFrame);
1094 if (addDirectionArrow) {
1095 _directionArrows.
append(segment);
1097 if (visualItem->
isCurrentItem() && _delayedSplitSegmentUpdate) {
1098 _splitSegment = segment;
1099 _delayedSplitSegmentUpdate =
false;
1100 signalSplitSegmentChanged =
true;
1104 firstCoordinateNotFound =
false;
1105 lastFlyThroughVI = visualItem;
1110 if (linkEndToHome && lastFlyThroughVI != _settingsItem && homePositionValid) {
1111 lastSegmentVisualItemPair =
VisualItemPair(lastFlyThroughVI, _settingsItem);
1112 FlightPathSegment* segment = _addFlightPathSegment(oldSegmentTable, lastSegmentVisualItemPair,
false );
1118 if (lastSegmentVisualItemPair.first) {
1124 if (_flightPathSegmentHashTable.contains(lastSegmentVisualItemPair)) {
1126 coordVector = _flightPathSegmentHashTable[lastSegmentVisualItemPair];
1127 }
else if (oldSegmentTable.contains(lastSegmentVisualItemPair)) {
1129 _flightPathSegmentHashTable[lastSegmentVisualItemPair] = coordVector = oldSegmentTable.take(lastSegmentVisualItemPair);
1134 lastSegmentVisualItemPair.first->isSimpleItem() ? lastSegmentVisualItemPair.first->entryCoordinate() : lastSegmentVisualItemPair.first->exitCoordinate(),
1135 lastSegmentVisualItemPair.first->isSimpleItem() ? lastSegmentVisualItemPair.first->amslEntryAlt() : lastSegmentVisualItemPair.first->amslExitAlt(),
1136 lastSegmentVisualItemPair.second->entryCoordinate(),
1137 lastSegmentVisualItemPair.second->amslEntryAlt(),
1140 _flightPathSegmentHashTable[lastSegmentVisualItemPair] = coordVector;
1143 _directionArrows.
append(coordVector);
1150 qDeleteAll(oldSegmentTable);
1155 if (signalSplitSegmentChanged) {
1160void MissionController::_recalcMissionFlightStatus()
1162 if (!_visualItems->
count()) {
1166 qCDebug(MissionControllerLog) <<
"_recalcMissionFlightStatus";
1168 _flightStatusCalc.
recalc(_visualItems, _settingsItem, _controllerVehicle, _managerVehicle, _appSettings, _planViewSettings, _missionContainsVTOLTakeoff);
1169 _missionFlightStatus = _flightStatusCalc.
status();
1192void MissionController::_recalcSequence(
void)
1194 if (_inRecalcSequence) {
1201 _inRecalcSequence =
true;
1202 int sequenceNumber = 0;
1203 for (
int i=0; i<_visualItems->
count(); i++) {
1208 _inRecalcSequence =
false;
1212void MissionController::_recalcChildItems(
void)
1218 for (
int i=1; i<_visualItems->
count(); i++) {
1227 currentParentItem = item;
1238void MissionController::_setupTreeModel(
void)
1242 _visualItemsTree.
clear();
1245 _planFileGroupNode.setObjectName(tr(
"Plan Info"));
1246 _visualItemsTree.
appendItem(&_planFileGroupNode, QModelIndex(), QStringLiteral(
"planFileGroup"));
1248 _planFileInfoMarker.setObjectName(QStringLiteral(
"planFileInfo"));
1249 _visualItemsTree.
appendItem(&_planFileInfoMarker,
1250 _visualItemsTree.
indexForObject(&_planFileGroupNode), QStringLiteral(
"planFileInfo"));
1253 _defaultsGroupNode.setObjectName(tr(
"Defaults"));
1254 _visualItemsTree.
appendItem(&_defaultsGroupNode, QModelIndex(), QStringLiteral(
"defaultsGroup"));
1256 _defaultsInfoMarker.setObjectName(QStringLiteral(
"defaultsInfo"));
1257 _visualItemsTree.
appendItem(&_defaultsInfoMarker,
1258 _visualItemsTree.
indexForObject(&_defaultsGroupNode), QStringLiteral(
"defaultsInfo"));
1261 _missionItemsGroupNode.setObjectName(tr(
"Mission Items"));
1262 _visualItemsTree.
appendItem(&_missionItemsGroupNode, QModelIndex(), QStringLiteral(
"missionGroup"));
1265 _fenceGroupNode.setObjectName(tr(
"GeoFence"));
1266 _visualItemsTree.
appendItem(&_fenceGroupNode, QModelIndex(), QStringLiteral(
"fenceGroup"));
1269 _fenceEditorMarker.setObjectName(QStringLiteral(
"fenceEditor"));
1270 _visualItemsTree.
appendItem(&_fenceEditorMarker,
1271 _visualItemsTree.
indexForObject(&_fenceGroupNode), QStringLiteral(
"fenceEditor"));
1274 _rallyGroupNode.setObjectName(tr(
"Rally Points"));
1275 _visualItemsTree.
appendItem(&_rallyGroupNode, QModelIndex(), QStringLiteral(
"rallyGroup"));
1278 _rallyHeaderMarker.setObjectName(QStringLiteral(
"rallyHeader"));
1279 _visualItemsTree.
appendItem(&_rallyHeaderMarker,
1280 _visualItemsTree.
indexForObject(&_rallyGroupNode), QStringLiteral(
"rallyHeader"));
1283 _transformGroupNode.setObjectName(tr(
"Transform"));
1284 _visualItemsTree.
appendItem(&_transformGroupNode, QModelIndex(), QStringLiteral(
"transformGroup"));
1287 _transformEditorMarker.setObjectName(QStringLiteral(
"transformEditor"));
1288 _visualItemsTree.
appendItem(&_transformEditorMarker,
1289 _visualItemsTree.
indexForObject(&_transformGroupNode), QStringLiteral(
"transformEditor"));
1294 _planFileGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_planFileGroupNode));
1295 _defaultsGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_defaultsGroupNode));
1296 _missionGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_missionItemsGroupNode));
1297 _fenceGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_fenceGroupNode));
1298 _rallyGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_rallyGroupNode));
1299 _transformGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_transformGroupNode));
1306void MissionController::_syncTreeMissionItemsInserted(
const QModelIndex& parent,
int first,
int last)
1309 for (
int i = first; i <= last; i++) {
1312 _visualItemsTree.
insertItem(i, item, _missionGroupIndex, QStringLiteral(
"missionItem"));
1317void MissionController::_syncTreeMissionItemsAboutToBeRemoved(
const QModelIndex& parent,
int first,
int last)
1321 for (
int i = last; i >= first; i--) {
1322 _visualItemsTree.
removeAt(_missionGroupIndex, i);
1326void MissionController::_syncTreeMissionItemsReset(
void)
1333 for (
int i = 0; i < _visualItems->
count(); i++) {
1336 _visualItemsTree.
appendItem(item, _missionGroupIndex, QStringLiteral(
"missionItem"));
1346void MissionController::_syncTreeRallyPointsInserted(
const QModelIndex& parent,
int first,
int last)
1350 if (!rallyController)
return;
1353 if (first == 0 && _visualItemsTree.
rowCount(_rallyGroupIndex) == 1) {
1354 const QModelIndex child = _visualItemsTree.
index(0, 0, _rallyGroupIndex);
1360 auto* pts = rallyController->points();
1361 for (
int i = first; i <= last; i++) {
1362 _visualItemsTree.
insertItem(i, (*pts)[i], _rallyGroupIndex, QStringLiteral(
"rallyItem"));
1366void MissionController::_syncTreeRallyPointsAboutToBeRemoved(
const QModelIndex& parent,
int first,
int last)
1369 for (
int i = last; i >= first; i--) {
1370 _visualItemsTree.
removeAt(_rallyGroupIndex, i);
1374void MissionController::_syncTreeRallyPointsRemoved(
const QModelIndex& parent,
int first,
int last)
1382 if (rallyController && rallyController->points()->count() == 0) {
1383 _rallyHeaderMarker.setObjectName(QStringLiteral(
"rallyHeader"));
1384 _visualItemsTree.
appendItem(&_rallyHeaderMarker, _rallyGroupIndex, QStringLiteral(
"rallyHeader"));
1388void MissionController::_syncTreeRallyPointsReset(
void)
1396 if (rallyController && rallyController->points()->count() > 0) {
1397 auto* pts = rallyController->
points();
1398 for (
int i = 0; i < pts->count(); i++) {
1399 _visualItemsTree.
appendItem((*pts)[i], _rallyGroupIndex, QStringLiteral(
"rallyItem"));
1402 _rallyHeaderMarker.setObjectName(QStringLiteral(
"rallyHeader"));
1403 _visualItemsTree.
appendItem(&_rallyHeaderMarker, _rallyGroupIndex, QStringLiteral(
"rallyHeader"));
1407void MissionController::_setPlannedHomePositionFromFirstCoordinate(
const QGeoCoordinate& clickCoordinate)
1409 bool foundFirstCoordinate =
false;
1410 QGeoCoordinate firstCoordinate;
1417 for (
int i=1; i<_visualItems->
count(); i++) {
1421 foundFirstCoordinate =
true;
1428 if (!foundFirstCoordinate) {
1429 firstCoordinate = clickCoordinate;
1432 if (firstCoordinate.isValid()) {
1433 QGeoCoordinate plannedHomeCoord = firstCoordinate.atDistanceAndAzimuth(30, 0);
1434 plannedHomeCoord.setAltitude(0);
1439void MissionController::_recalcAllWithCoordinate(
const QGeoCoordinate& coordinate)
1442 _setPlannedHomePositionFromFirstCoordinate(coordinate);
1445 _recalcChildItems();
1450void MissionController::_recalcAll(
void)
1452 QGeoCoordinate emptyCoord;
1453 _recalcAllWithCoordinate(emptyCoord);
1457void MissionController::_initAllVisualItems(
void)
1461 if (!_settingsItem) {
1462 _settingsItem = qobject_cast<MissionSettingsItem*>(_visualItems->
get(0));
1463 if (!_settingsItem) {
1464 qWarning() <<
"First item not MissionSettingsItem";
1473 for (
int i=0; i<_visualItems->
count(); i++) {
1475 _initVisualItem(item);
1479 _takeoffMissionItem = takeoffItem;
1489 connect(_visualItems, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeMissionItemsInserted);
1490 connect(_visualItems, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeMissionItemsAboutToBeRemoved);
1491 connect(_visualItems, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeMissionItemsReset);
1494 _syncTreeMissionItemsReset();
1498 if (rallyController) {
1499 auto* pts = rallyController->
points();
1500 connect(pts, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeRallyPointsInserted);
1501 connect(pts, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeRallyPointsAboutToBeRemoved);
1502 connect(pts, &QAbstractItemModel::rowsRemoved,
this, &MissionController::_syncTreeRallyPointsRemoved);
1503 connect(pts, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeRallyPointsReset);
1506 _syncTreeRallyPointsReset();
1521void MissionController::_deinitAllVisualItems(
void)
1527 for (
int i=0; i<_visualItems->
count(); i++) {
1528 _deinitVisualItem(qobject_cast<VisualMissionItem*>(_visualItems->
get(i)));
1535 disconnect(_visualItems, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeMissionItemsInserted);
1536 disconnect(_visualItems, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeMissionItemsAboutToBeRemoved);
1537 disconnect(_visualItems, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeMissionItemsReset);
1541 if (rallyController) {
1542 auto* pts = rallyController->
points();
1543 disconnect(pts, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeRallyPointsInserted);
1544 disconnect(pts, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeRallyPointsAboutToBeRemoved);
1545 disconnect(pts, &QAbstractItemModel::rowsRemoved,
this, &MissionController::_syncTreeRallyPointsRemoved);
1546 disconnect(pts, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeRallyPointsReset);
1570 qWarning() <<
"isSimpleItem == true, yet not SimpleMissionItem";
1581 qWarning() <<
"ComplexMissionItem not found";
1591 disconnect(visualItem,
nullptr,
this,
nullptr);
1594void MissionController::_itemCommandChanged(
void)
1596 _recalcChildItems();
1600void MissionController::_managerVehicleChanged(
Vehicle* managerVehicle)
1602 if (_managerVehicle) {
1603 _missionManager->disconnect(
this);
1604 _managerVehicle->disconnect(
this);
1605 _managerVehicle =
nullptr;
1606 _missionManager =
nullptr;
1609 _managerVehicle = managerVehicle;
1610 if (!_managerVehicle) {
1611 qWarning() <<
"MissionController::managerVehicleChanged managerVehicle=NULL";
1633void MissionController::_inProgressChanged(
bool inProgress)
1641 double foundAltitude = 0;
1644 if (newIndex > _visualItems->
count()) {
1649 for (
int i=newIndex; i>0; i--) {
1666 *prevAltitude = foundAltitude;
1667 *prevAltitudeMode = foundAltFrame;
1673double MissionController::_normalizeLat(
double lat)
1679double MissionController::_normalizeLon(
double lon)
1688 qCDebug(MissionControllerLog) <<
"_addMissionSettings";
1694 _settingsItem = settingsItem;
1697 return settingsItem;
1703 int resumeIndex = 0;
1727 return currentIndex;
1731void MissionController::_currentMissionIndexChanged(
int sequenceNumber)
1738 for (
int i=0; i<_visualItems->
count(); i++) {
1753 return _visualItems ? _visualItems->
dirty() :
false;
1772 while (scanIndex < visualItems->count()) {
1775 qCDebug(MissionControllerLog) <<
"MissionController::_scanForAdditionalSettings count:scanIndex" <<
visualItems->
count() << scanIndex;
1799 return _visualItems ? _visualItems->
count() > 1 :
false;
1805 qCCritical(MissionControllerLog) <<
"MissionControllerLog::removeAllFromVehicle called while offline";
1807 qCCritical(MissionControllerLog) <<
"MissionControllerLog::removeAllFromVehicle called while syncInProgress";
1809 _itemsRequested =
true;
1829 if (_settingsItem) {
1832 return QGeoCoordinate();
1838 return _settingsItem && _settingsItem->
coordinate().isValid();
1843 if (_settingsItem) {
1850 double defaultAltitude = _appSettings->defaultMissionItemAltitude()->rawValue().toDouble();
1852 for (
int i=1; i<_visualItems->
count(); i++) {
1858void MissionController::_progressPctChanged(
double progressPct)
1866void MissionController::_visualItemsDirtyChanged(
bool dirty)
1874 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle _flyView" <<
_flyView;
1876 qCCritical(MissionControllerLog) <<
"MissionController::showPlanFromManagerVehicle called while offline";
1881 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal";
1885 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle: syncInProgress wait for signal";
1889 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle: sync complete simulate signal";
1890 _itemsRequested =
true;
1891 _newMissionItemsAvailableFromVehicle(
false );
1897void MissionController::_managerSendComplete(
bool error)
1905void MissionController::_managerRemoveAllComplete(
bool error)
1915 return simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI_LOCATION ||
1916 simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI_WPNEXT_OFFSET ||
1917 (simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI &&
1923 return simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI_NONE ||
1924 (simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI &&
1930 if (_visualItems && (force || sequenceNumber != _currentPlanViewSeqNum)) {
1931 qCDebug(MissionControllerLog) <<
"setCurrentPlanViewSeqNum";
1932 bool foundLand =
false;
1933 bool onlyInsertTakeoffValid =
false;
1934 int takeoffSeqNum = -1;
1935 int landSeqNum = -1;
1936 int lastFlyThroughSeqNum = -1;
1938 _splitSegment =
nullptr;
1939 _currentPlanViewItem =
nullptr;
1940 _currentPlanViewSeqNum = -1;
1941 _currentPlanViewVIIndex = -1;
1942 _isInsertTakeoffValid =
true;
1943 _isInsertLandValid =
true;
1944 _isInsertROIValid =
false;
1945 _isROIActive =
false;
1946 _isROIBeginCurrentItem =
false;
1947 _flyThroughCommandsAllowed =
true;
1948 _previousCoordinate = QGeoCoordinate();
1950 bool noItemsAddedYet = _visualItems->
count() == 1;
1952 onlyInsertTakeoffValid =
true;
1955 for (
int viIndex=0; viIndex<_visualItems->
count(); viIndex++) {
1960 if (sequenceNumber != 0 && currentSeqNumber <= sequenceNumber) {
1963 _isInsertTakeoffValid =
false;
1967 if (qobject_cast<TakeoffMissionItem*>(pVI)) {
1968 takeoffSeqNum = currentSeqNumber;
1969 _isInsertTakeoffValid =
false;
1975 case MAV_CMD_NAV_LAND:
1976 case MAV_CMD_NAV_VTOL_LAND:
1977 case MAV_CMD_DO_LAND_START:
1978 case MAV_CMD_NAV_RETURN_TO_LAUNCH:
1980 landSeqNum = currentSeqNumber;
1989 landSeqNum = currentSeqNumber;
1996 if (currentSeqNumber < sequenceNumber && simpleItem->specifiesCoordinate() && !simpleItem->
isStandaloneCoordinate()) {
1997 _previousCoordinate = simpleItem->
coordinate();
2001 if (currentSeqNumber <= sequenceNumber) {
2003 if (_isROICancelItem(simpleItem)) {
2004 _isROIActive =
false;
2007 if (_isROIBeginItem(simpleItem)) {
2008 _isROIActive =
true;
2012 if (currentSeqNumber == sequenceNumber && _isROIBeginItem(simpleItem)) {
2013 _isROIBeginCurrentItem =
true;
2020 lastFlyThroughSeqNum = currentSeqNumber;
2024 if (currentSeqNumber == sequenceNumber) {
2028 _currentPlanViewItem = pVI;
2029 _currentPlanViewSeqNum = sequenceNumber;
2030 _currentPlanViewVIIndex = viIndex;
2035 for (
int j=viIndex-1; j>0; j--) {
2039 if (_flightPathSegmentHashTable.contains(splitPair)) {
2040 _splitSegment = _flightPathSegmentHashTable[splitPair];
2044 _delayedSplitSegmentUpdate =
true;
2060 if (takeoffSeqNum != -1) {
2062 if (sequenceNumber < takeoffSeqNum) {
2064 _isInsertLandValid =
false;
2066 _flyThroughCommandsAllowed =
false;
2070 if (lastFlyThroughSeqNum != -1) {
2072 if (sequenceNumber < lastFlyThroughSeqNum) {
2073 _isInsertLandValid =
false;
2078 _isInsertLandValid =
false;
2079 if (sequenceNumber >= landSeqNum) {
2081 _flyThroughCommandsAllowed =
false;
2085 if (_hasLandItem != foundLand) {
2087 _hasLandItem = foundLand;
2092 _isInsertLandValid = _isInsertLandValid && !onlyInsertTakeoffValid;
2093 _flyThroughCommandsAllowed = _flyThroughCommandsAllowed && !onlyInsertTakeoffValid;
2097 _isInsertTakeoffValid = _isInsertTakeoffValid && homePosSet;
2098 _isInsertLandValid = _isInsertLandValid && homePosSet;
2099 _flyThroughCommandsAllowed = _flyThroughCommandsAllowed && homePosSet;
2100 _isInsertROIValid = homePosSet && !onlyInsertTakeoffValid;
2112 bool repositionTakeoffItems,
2113 bool repositionLandingItems)
2115 if (!newHome.isValid()) {
2116 qCWarning(MissionControllerLog) <<
"Cannot reposition mission to an invalid coordinate";
2120 if (!_settingsItem || !_settingsItem->
coordinate().isValid()) {
2121 qCWarning(MissionControllerLog) <<
"Cannot reposition mission while home is invalid";
2125 const QGeoCoordinate oldHome = _settingsItem->
coordinate();
2127 for (
int i = 0; i < _visualItems->
count(); ++i) {
2128 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2138 const QGeoCoordinate oldCoord = item->
coordinate();
2139 if (!oldCoord.isValid()) {
2143 const double distanceMeters = oldHome.distanceTo(oldCoord);
2144 const double azimuthDegrees = oldHome.azimuthTo(oldCoord);
2146 QGeoCoordinate newCoord = newHome.atDistanceAndAzimuth(distanceMeters, azimuthDegrees);
2156 bool offsetTakeoffItems,
2157 bool offsetLandingItems)
2159 if (!qFuzzyIsNull(eastMeters) || !qFuzzyIsNull(northMeters)) {
2160 const double distanceMeters = qSqrt(eastMeters * eastMeters + northMeters * northMeters);
2161 double azimuthDegrees = 0.0;
2162 if (!qFuzzyIsNull(distanceMeters)) {
2163 const double azimuthRadians = qAtan2(eastMeters, northMeters);
2164 azimuthDegrees = qRadiansToDegrees(azimuthRadians);
2167 for (
int i = 0; i < _visualItems->
count(); ++i) {
2168 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2178 const QGeoCoordinate oldCoord = item->
coordinate();
2179 if (!oldCoord.isValid()) {
2183 item->
setCoordinate(oldCoord.atDistanceAndAzimuth(distanceMeters, azimuthDegrees));
2189 if (!qFuzzyIsNull(upMeters)) {
2190 for (
int i = 0; i < _visualItems->
count(); ++i) {
2191 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2192 if (!item || item == _settingsItem) {
2215 bool rotateTakeoffItems,
2216 bool rotateLandingItems)
2218 if (qFuzzyIsNull(degreesCW)) {
2222 if (!_settingsItem || !_settingsItem->
coordinate().isValid()) {
2223 qCWarning(MissionControllerLog) <<
"Cannot rotate mission while home is invalid";
2227 const QGeoCoordinate home = _settingsItem->
coordinate();
2229 for (
int i = 0; i < _visualItems->
count(); ++i) {
2230 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2240 const QGeoCoordinate oldCoord = item->
coordinate();
2241 if (!oldCoord.isValid()) {
2245 const double distanceMeters = home.distanceTo(oldCoord);
2246 if (qFuzzyIsNull(distanceMeters)) {
2249 const double azimuthDegrees = home.azimuthTo(oldCoord);
2251 QGeoCoordinate newCoord = home.atDistanceAndAzimuth(distanceMeters, azimuthDegrees + degreesCW);
2258void MissionController::_updateTimeout()
2260 QGeoCoordinate firstCoordinate;
2264 double south = 180.0;
2266 double west = 360.0;
2269 for (
int i = 1; i < _visualItems->
count(); i++) {
2274 switch(pSimpleItem->
command()) {
2275 case MAV_CMD_NAV_TAKEOFF:
2276 case MAV_CMD_NAV_WAYPOINT:
2277 case MAV_CMD_NAV_LAND:
2283 if((MAV_CMD)pSimpleItem->
command() == MAV_CMD_NAV_TAKEOFF) {
2286 minAlt = maxAlt = alt;
2287 }
else if(!firstCoordinate.isValid()) {
2290 double lat = pSimpleItem->
coordinate().latitude() + 90.0;
2291 double lon = pSimpleItem->
coordinate().longitude() + 180.0;
2292 north = fmax(north, lat);
2293 south = fmin(south, lat);
2294 east = fmax(east, lon);
2295 west = fmin(west, lon);
2296 minAlt = fmin(minAlt, alt);
2297 maxAlt = fmax(maxAlt, alt);
2309 if(!firstCoordinate.isValid() && pComplexItem->
entryCoordinate().isValid()) {
2312 north = fmax(north, bc.
pointNW.latitude() + 90.0);
2313 south = fmin(south, bc.
pointSE.latitude() + 90.0);
2314 east = fmax(east, bc.
pointNW.longitude() + 180.0);
2315 west = fmin(west, bc.
pointSE.longitude() + 180.0);
2316 minAlt = fmin(minAlt, bc.
pointNW.altitude());
2317 maxAlt = fmax(maxAlt, bc.
pointSE.altitude());
2324 if(firstCoordinate.isValid()) {
2332 QGeoCoordinate(north - 90.0, west - 180.0, minAlt),
2333 QGeoCoordinate(south - 90.0, east - 180.0, maxAlt));
2334 if(_travelBoundingCube != boundingCube || _takeoffCoordinate !=
takeoffCoordinate) {
2336 _travelBoundingCube = boundingCube;
2338 qCDebug(MissionControllerLog) <<
"Bounding cube:" << _travelBoundingCube.
pointNW << _travelBoundingCube.
pointSE;
2342void MissionController::_complexBoundingBoxChanged()
2348 const int count = _visualItems->
count();
2350 for (
int i = 0; i < count; i++) {
2351 QObject *obj = _visualItems->
get(i);
2355 return landingItem == item;
2364 return _visualItems->
count() <= 1;
2367void MissionController::_recalcPlanViewState(
void)
2372void MissionController::_allItemsRemoved(
void)
2379void MissionController::_firstItemAdded(
void)
2402 return _globalAltFrame;
2410 return _globalAltFrame;
2416 if (_globalAltFrame != altFrame) {
2417 _globalAltFrame = altFrame;
#define UPDATE_TIMEOUT
How often we check for bounding box changes.
QPair< VisualMissionItem *, VisualMissionItem * > VisualItemPair
QHash< VisualItemPair, FlightPathSegment * > FlightPathSegmentHashTable
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void setSpecifyCameraMode(bool specifyCameraMode)
void setSpecifyGimbal(bool specifyGimbal)
bool specifyCameraMode(void) const
bool cameraModeSupported(void) const
bool specifyGimbal(void) const
void isIncompleteChanged(void)
void boundingCubeChanged(void)
static constexpr const char * jsonComplexItemTypeKey
This mission item attribute specifies the type of the complex item.
void greatestDistanceToChanged(void)
bool isIncomplete(void) const
virtual void applyPreviousAltitudeFrame(QGroundControlQmlGlobal::AltitudeFrame prevAltFrame, double prevAltitude)
void maxAMSLAltitudeChanged(void)
virtual bool load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString)=0
void minAMSLAltitudeChanged(void)
void complexDistanceChanged(void)
void rawValueChanged(const QVariant &value)
void setRawValue(const QVariant &value)
QVariant rawValue() const
Value after translation.
void valueChanged(const QVariant &value)
This signal is only meant for use by the QT property system. It should not be connected to by client ...
virtual QList< MAV_CMD > supportedMissionCommands(QGCMAVLinkTypes::VehicleClass_t) const
List of supported mission commands. Empty list for all commands supported.
virtual bool sendHomePositionToVehicle() const
virtual bool hasGimbal(Vehicle *vehicle, bool &rollSupported, bool &pitchSupported, bool &yawSupported) const
static bool scanForItems(QmlObjectListModel *visualItems, bool flyView, PlanMasterController *masterController)
Scans the loaded items for a landing pattern complex item.
static constexpr const char * canonicalName
void terrainCollisionChanged(bool terrainCollision)
void totalDistanceChanged(double totalDistance)
void setCoordinate2(const QGeoCoordinate &coordinate)
void coord2AMSLAltChanged(void)
@ SegmentTypeTerrainFrame
void coord1AMSLAltChanged(void)
void setSpecialVisual(bool specialVisual)
void amslTerrainHeightsChanged(void)
void setCoord2AMSLAlt(double alt)
void setCoord1AMSLAlt(double alt)
void setCoordinate1(const QGeoCoordinate &coordinate)
Used to convert a Plan to a KML document.
void addMission(Vehicle *vehicle, QmlObjectListModel *visualItems, QList< MissionItem * > rgMissionItems)
static MissionCommandTree * instance()
void minAMSLAltitudeChanged(double minAMSLAltitude)
Q_INVOKABLE void resumeMission(int resumeIndex)
double progressPct(void) const
Q_INVOKABLE int visualItemIndexForObject(QObject *object) const
Returns the visual item index for the given VisualMissionItem object, or -1 if not found.
void complexMissionItemsChanged(void)
Q_INVOKABLE void setHomePosition(QGeoCoordinate coordinate)
Set the planned home position from a map click.
bool showPlanFromManagerVehicle(void) final
Q_INVOKABLE SendToVehiclePreCheckState sendToVehiclePreCheck(void)
bool dirty(void) const final
Q_INVOKABLE VisualMissionItem * insertComplexMissionItem(QString itemName, QGeoCoordinate mapCenterCoordinate, int visualItemIndex, bool makeCurrentItem=false)
void batteriesRequiredChanged(int batteriesRequired)
bool loadTextFile(QFile &file, QString &errorString)
void multipleLandPatternsAllowedChanged(void)
bool multipleLandPatternsAllowed(void) const
Q_INVOKABLE VisualMissionItem * insertTakeoffItem(QGeoCoordinate coordinate, int visualItemIndex, bool makeCurrentItem=false)
QGeoCoordinate takeoffCoordinate()
Q_INVOKABLE VisualMissionItem * insertLandItem(QGeoCoordinate coordinate, int visualItemIndex, bool makeCurrentItem=false)
Q_INVOKABLE void offsetMission(double eastMeters, double northMeters, double upMeters=0.0, bool offsetTakeoffItems=false, bool offsetLandingItems=false)
Q_INVOKABLE void setCurrentPlanViewSeqNum(int sequenceNumber, bool force)
void maxAMSLAltitudeChanged(double maxAMSLAltitude)
void removeAllFromVehicle(void) final
void homePositionSetChanged(void)
void recalcTerrainProfile(void)
void missionPlannedDistanceChanged(double missionPlannedDistance)
void missionTotalDistanceChanged(double missionTotalDistance)
void hasLandItemChanged(void)
void _recalcFlightPathSegmentsSignal(void)
int currentMissionIndex(void) const
void missionMaxTelemetryChanged(double missionMaxTelemetry)
static void sendItemsToVehicle(Vehicle *vehicle, QmlObjectListModel *visualMissionItems)
Sends the mission items to the specified vehicle.
bool load(const QJsonObject &json, QString &errorString) final
void splitSegmentChanged(void)
Q_INVOKABLE void repositionMission(const QGeoCoordinate &newHome, bool repositionTakeoffItems=true, bool repositionLandingItems=true)
void resumeMissionReady(void)
SendToVehiclePreCheckState
@ SendToVehiclePreCheckStateFirwmareVehicleMismatch
@ SendToVehiclePreCheckStateNoActiveVehicle
@ SendToVehiclePreCheckStateOk
@ SendToVehiclePreCheckStateActiveMission
void batteryChangePointChanged(int batteryChangePoint)
Q_INVOKABLE void rotateMission(double degreesCW, bool rotateTakeoffItems=false, bool rotateLandingItems=false)
void addMissionToKML(KMLPlanDomDocument &planKML)
void _recalcMissionFlightStatusSignal(void)
void missionHoverDistanceChanged(double missionHoverDistance)
bool syncInProgress(void) const final
void sendToVehicle(void) final
void resumeMissionIndexChanged(void)
void currentMissionIndexChanged(int currentMissionIndex)
Q_INVOKABLE VisualMissionItem * insertROIMissionItem(QGeoCoordinate coordinate, int visualItemIndex, bool makeCurrentItem=false)
void plannedHomePositionChanged(QGeoCoordinate plannedHomePosition)
Q_INVOKABLE void removeVisualItem(int viIndex)
void newItemsFromVehicle(void)
void setGlobalAltitudeFrame(QGroundControlQmlGlobal::AltitudeFrame altFrame)
void save(QJsonObject &json) final
Q_INVOKABLE VisualMissionItem * insertSimpleMissionItem(QGeoCoordinate coordinate, int visualItemIndex, bool makeCurrentItem=false)
void missionHoverTimeChanged(void)
bool isFirstLandingComplexItem(const LandingComplexItem *item) const
QGeoCoordinate plannedHomePosition(void) const
bool homePositionSet(void) const
bool containsItems(void) const final
void progressPctChanged(double progressPct)
void missionCruiseTimeChanged(void)
QGroundControlQmlGlobal::AltitudeFrame globalAltitudeFrame(void)
int readyForSaveState(void) const
QGroundControlQmlGlobal::AltitudeFrame globalAltitudeFrameDefault(void)
void removeAll(void) final
Removes all from controller only.
void visualItemsReset(void)
void missionBoundingCubeChanged(void)
QVariantList complexMissionItems(void) const
void missionTimeChanged(void)
Q_INVOKABLE void applyDefaultMissionAltitude(void)
Updates the altitudes of the items in the current mission to the new default altitude.
void setDirty(bool dirty) final
void start(bool flyView) final
Should be called immediately upon Component.onCompleted.
void planViewStateChanged(void)
All plan-view properties are recomputed together in setCurrentPlanViewSeqNum, so one signal covers th...
void globalAltitudeFrameChanged(void)
void missionCruiseDistanceChanged(double missionCruiseDistance)
void resumeMissionUploadFail(void)
void loadFromVehicle(void) final
Q_INVOKABLE VisualMissionItem * insertCancelROIMissionItem(int visualItemIndex, bool makeCurrentItem=false)
int resumeMissionIndex(void) const
Q_INVOKABLE VisualMissionItem * insertComplexMissionItemFromKMLOrSHP(QString itemName, QString file, int visualItemIndex, bool makeCurrentItem=false)
QmlObjectListModel * visualItems(void)
void reset(Vehicle *controllerVehicle, Vehicle *managerVehicle, bool missionContainsVTOLTakeoff)
Resets the flight status fields to defaults based on vehicle properties.
double maxAMSLAltitude() const
const MissionFlightStatus_t & status() const
double minAMSLAltitude() const
void recalc(QmlObjectListModel *visualItems, MissionSettingsItem *settingsItem, Vehicle *controllerVehicle, Vehicle *managerVehicle, AppSettings *appSettings, PlanViewSettings *planViewSettings, bool missionContainsVTOLTakeoff)
void setParam1(double param1)
MAV_FRAME frame(void) const
void save(QJsonObject &json) const
double param1(void) const
QGeoCoordinate coordinate(void) const
int lastCurrentIndex(void) const
Last current mission item reported while in Mission flight mode.
void generateResumeMission(int resumeIndex)
int currentIndex(void) const
Current mission item as reported by MISSION_CURRENT.
bool scanForMissionSettings(QmlObjectListModel *visualItems, int scanIndex)
Scans the loaded items for settings items.
QGeoCoordinate coordinate(void) const final
void setCoordinate(const QGeoCoordinate &coordinate) final
bool addMissionEndAction(QList< MissionItem * > &items, int seqNum, QObject *missionItemParent)
CameraSection * cameraSection(void)
void endResetModel()
Depth-counted endResetModel — only the outermost call has effect.
void beginResetModel()
Depth-counted beginResetModel — only the outermost call has effect.
void dirtyChanged(bool dirty)
void countChanged(int count)
This is the abstract base clas for Plan Element controllers.
void syncInProgressChanged(bool syncInProgress)
PlanMasterController * masterController(void)
PlanMasterController * _masterController
virtual void start(bool flyView)
Should be called immediately upon Component.onCompleted.
void containsItemsChanged()
void dirtyChanged(bool dirty)
void resumeMissionUploadFail(void)
void currentIndexChanged(int currentIndex)
void lastCurrentIndexChanged(int lastCurrentIndex)
void sendComplete(bool error)
void resumeMissionReady(void)
void newMissionItemsAvailable(bool removeAllRequested)
void loadFromVehicle(void)
void removeAllComplete(bool error)
void writeMissionItems(const QList< MissionItem * > &missionItems)
bool inProgress(void) const
void inProgressChanged(bool inProgress)
void progressPctChanged(double progressPercentPct)
const QList< MissionItem * > & missionItems(void)
Master controller for mission, fence, rally.
Vehicle * controllerVehicle(void)
void managerVehicleChanged(Vehicle *managerVehicle)
RallyPointController * rallyPointController(void)
Vehicle * managerVehicle(void)
virtual ComplexMissionItem * createComplexMissionItem(const QString &complexItemType, PlanMasterController *masterController, bool flyView, const QString &kmlOrShpFile=QString())
virtual QVariantList complexMissionItemNames(Vehicle *vehicle)
static QGCCorePlugin * instance()
Q_INVOKABLE bool isValid() const
static VehicleClass_t vehicleClass(MAV_TYPE mavType)
static MAV_TYPE vehicleClassToMavType(VehicleClass_t vehicleClass)
static FirmwareClass_t firmwareClass(MAV_AUTOPILOT autopilot)
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
void setDirty(bool dirty) override final
Q_INVOKABLE QObject * get(int index)
QObject * removeAt(int index)
int count() const override final
void clear() override final
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
void insert(int index, QObject *object)
int indexOf(const QObject *object)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
static constexpr int NodeTypeRole
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void removeChildren(const QModelIndex &parentIndex)
Removes all children of parentIndex without removing the parent itself.
Q_INVOKABLE QObject * removeItem(const QModelIndex &index)
QObject * removeAt(const QModelIndex &parentIndex, int row)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE QModelIndex indexForObject(QObject *object) const
Searches the entire tree for object and returns its QModelIndex (invalid if not found)
Q_INVOKABLE QModelIndex insertItem(int row, QObject *object, const QModelIndex &parentIndex=QModelIndex())
Inserts object at row under parentIndex. Returns the new item's index.
Q_INVOKABLE QModelIndex appendItem(QObject *object, const QModelIndex &parentIndex=QModelIndex())
Appends object as the last child of parentIndex (root if invalid). Returns the new item's index.
QmlObjectListModel * points(void)
Provides access to all app settings.
static SettingsManager * instance()
AppSettings * appSettings() const
A SimpleMissionItem is used to represent a single MissionItem to the ui.
bool specifiesCoordinate(void) const final
void setSequenceNumber(int sequenceNumber) final
bool isStandaloneCoordinate(void) const final
int sequenceNumber(void) const final
bool scanForSections(QmlObjectListModel *visualItems, int scanIndex, PlanMasterController *masterController)
int lastSequenceNumber(void) const final
MAV_CMD mavCommand(void) const
bool specifiesAltitude(void) const
QGeoCoordinate coordinate(void) const final
virtual bool load(QTextStream &loadStream)
void setCoordinate(const QGeoCoordinate &coordinate) override
void setCommand(int command)
void setAltitudeFrame(QGroundControlQmlGlobal::AltitudeFrame altitudeFrame)
MissionItem & missionItem(void)
QGroundControlQmlGlobal::AltitudeFrame altitudeFrame(void) const
Takeoff mission item is a special case of a SimpleMissionItem which supports Launch Location display/...
static bool isTakeoffCommand(MAV_CMD command)
bool load(QTextStream &loadStream) final
static constexpr const char * canonicalName
static bool scanForItems(QmlObjectListModel *visualItems, bool flyView, PlanMasterController *masterController)
Scans the loaded items for a landing pattern complex item.
bool takeoffMissionCommand() const
void defaultHoverSpeedChanged(double hoverSpeed)
void defaultCruiseSpeedChanged(double cruiseSpeed)
QString missionFlightMode() const
void _offlineVehicleTypeSettingChanged(QVariant varVehicleType)
QString flightMode() const
MAV_TYPE vehicleType() const
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
bool isOfflineEditingVehicle() const
MAV_AUTOPILOT firmwareType() const
void _offlineFirmwareTypeSettingChanged(QVariant varFirmwareType)
void trackFirmwareVehicleTypeChanges(void)
double defaultHoverSpeed() const
void stopTrackingFirmwareVehicleTypeChanges(void)
bool initialPlanRequestComplete() const
double defaultCruiseSpeed() const
VehicleSupports * supports()
MissionManager * missionManager()
void vehicleTypeChanged()
virtual int lastSequenceNumber(void) const =0
void setIsCurrentItem(bool isCurrentItem)
void setHasCurrentChildItem(bool hasCurrentChildItem)
void specifiedVehicleYawChanged(void)
virtual void setCoordinate(const QGeoCoordinate &coordinate)=0
virtual int sequenceNumber(void) const =0
virtual void applyNewAltitude(double newAltitude)=0
Adjust the altitude of the item if appropriate to the new altitude.
static constexpr const char * jsonTypeComplexItemValue
Item type is Complex Item.
virtual bool isTakeoffItem(void) const
virtual bool isStandaloneCoordinate(void) const =0
void amslExitAltChanged(double alt)
void setParentItem(VisualMissionItem *parentItem)
void terrainAltitudeChanged(double terrainAltitude)
void setWizardMode(bool wizardMode)
bool isCurrentItem(void) const
void lastSequenceNumberChanged(int sequenceNumber)
void entryCoordinateChanged(const QGeoCoordinate &entryCoordinate)
void specifiesCoordinateChanged(void)
void coordinateChanged(const QGeoCoordinate &coordinate)
void setSimpleFlighPathSegment(FlightPathSegment *segment)
void specifiedFlightSpeedChanged(void)
void clearSimpleFlighPathSegment(void)
void currentVTOLModeChanged(void)
Signals that this item has changed the VTOL mode (MAV_CMD_DO_VTOL_TRANSITION)
virtual void setSequenceNumber(int sequenceNumber)=0
virtual ReadyForSaveState readyForSaveState(void) const
void specifiedGimbalYawChanged(void)
void amslEntryAltChanged(double alt)
void specifiedGimbalPitchChanged(void)
static constexpr const char * jsonTypeKey
Json file attribute which specifies the item type.
virtual QGeoCoordinate coordinate(void) const =0
virtual bool specifiesAltitudeOnly(void) const =0
virtual void appendMissionItems(QList< MissionItem * > &items, QObject *missionItemParent)=0
virtual QString commandName(void) const =0
virtual bool isLandCommand(void) const
static constexpr const char * jsonTypeSimpleItemValue
Item type is MISSION_ITEM.
virtual QGCGeoBoundingCube * boundingCube(void)
virtual bool isSimpleItem(void) const =0
QmlObjectListModel * childItems(void)
virtual bool specifiesCoordinate(void) const =0
void exitCoordinateChanged(const QGeoCoordinate &exitCoordinate)
void additionalTimeDelayChanged(void)
virtual void save(QJsonArray &missionItems)=0
VisualMissionItem * parentItem(void)
virtual QGeoCoordinate entryCoordinate(void) const =0
virtual double editableAlt(void) const =0
bool loadGeoCoordinate(const QJsonValue &jsonValue, bool altitudeRequired, QGeoCoordinate &coordinate, QString &errorString)
void saveGeoCoordinate(const QGeoCoordinate &coordinate, bool writeAltitude, QJsonValue &jsonValue)
Saves a QGeoCoordinate as [lat, lon, alt] array (QGC plan format).
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
Validates that all required keys are present and that listed keys have the expected type.
constexpr const char * jsonVersionKey
bool fuzzyCompare(double value1, double value2)
Returns true if the two values are equal or close. Correctly handles 0 and NaN values.
int batteriesRequired
-1 for not supported
double maxTelemetryDistance
int batteryChangePoint
-1 for not supported, 0 for not needed
static constexpr VehicleClass_t VehicleClassGeneric