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, _missionStartsInVTOLMulticopterMode);
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 return _insertTakeoffItemWorker(
318 _controllerVehicle->
vtol() ? MAV_CMD_NAV_VTOL_TAKEOFF : MAV_CMD_NAV_TAKEOFF,
324 QGeoCoordinate ,
int visualItemIndex,
bool makeCurrentItem)
327 qCWarning(MissionControllerLog) <<
"Multicopter takeoff requested for an unsupported vehicle";
331 return _insertTakeoffItemWorker(MAV_CMD_NAV_TAKEOFF, visualItemIndex, makeCurrentItem);
334VisualMissionItem* MissionController::_insertTakeoffItemWorker(MAV_CMD command,
int visualItemIndex,
bool makeCurrentItem)
336 int sequenceNumber = _nextSequenceNumber();
339 _initVisualItem(_takeoffMissionItem);
345 if (_findPreviousAltitude(visualItemIndex, &prevAltitude, &prevAltFrame)) {
350 if (visualItemIndex == -1) {
351 _visualItems->
append(_takeoffMissionItem);
353 _visualItems->
insert(visualItemIndex, _takeoffMissionItem);
358 if (makeCurrentItem) {
364 return _takeoffMissionItem;
370 return (_controllerVehicle->
fixedWing() || _controllerVehicle->
vtol()) &&
371 _planViewSettings->allowMultipleLandingPatterns()
372 ->rawValue().toBool() &&
381 }
else if (_controllerVehicle->
vtol()) {
385 return _insertSimpleMissionItemWorker(coordinate, MAV_CMD_NAV_RETURN_TO_LAUNCH, visualItemIndex, makeCurrentItem);
391 SimpleMissionItem* simpleItem = qobject_cast<SimpleMissionItem*>(_insertSimpleMissionItemWorker(coordinate, MAV_CMD_DO_SET_ROI_LOCATION, visualItemIndex, makeCurrentItem));
402 SimpleMissionItem* simpleItem = qobject_cast<SimpleMissionItem*>(_insertSimpleMissionItemWorker(QGeoCoordinate(), MAV_CMD_DO_SET_ROI_NONE, visualItemIndex, makeCurrentItem));
422 if (_findPreviousAltitude(visualItemIndex, &prevAltitude, &prevAltFrame)) {
427 _insertComplexMissionItemWorker(mapCenterCoordinate, newItem, visualItemIndex, makeCurrentItem);
439 _insertComplexMissionItemWorker(QGeoCoordinate(), newItem, visualItemIndex, makeCurrentItem);
444void MissionController::_insertComplexMissionItemWorker(
const QGeoCoordinate& mapCenterCoordinate,
ComplexMissionItem* complexItem,
int visualItemIndex,
bool makeCurrentItem)
446 int sequenceNumber = _nextSequenceNumber();
447 bool surveyStyleItem = qobject_cast<SurveyComplexItem*>(complexItem) ||
448 qobject_cast<CorridorScanComplexItem*>(complexItem) ||
449 qobject_cast<StructureScanComplexItem*>(complexItem);
451 if (surveyStyleItem) {
452 bool rollSupported =
false;
453 bool pitchSupported =
false;
454 bool yawSupported =
false;
462 if (cameraSection->cameraModeSupported() && !cameraSection->specifyCameraMode()) {
464 cameraSection->cameraMode()->setRawValue(CAMERA_MODE_IMAGE_SURVEY);
468 if (_controllerVehicle->
firmwarePlugin()->
hasGimbal(_controllerVehicle, rollSupported, pitchSupported, yawSupported) && pitchSupported) {
470 if (!cameraSection->specifyGimbal()) {
471 cameraSection->setSpecifyGimbal(
true);
472 cameraSection->gimbalPitch()->setRawValue(-90.0);
478 if (!qobject_cast<VTOLLandingComplexItem*>(complexItem)) {
481 _initVisualItem(complexItem);
483 if (visualItemIndex == -1) {
484 _visualItems->
append(complexItem);
486 _visualItems->
insert(visualItemIndex, complexItem);
493 _recalcAllWithCoordinate(mapCenterCoordinate);
495 if (makeCurrentItem) {
503 return _visualItems ? _visualItems->
indexOf(
object) : -1;
508 if (viIndex <= 0 || viIndex >= _visualItems->
count()) {
509 qWarning() <<
"MissionController::removeVisualItem called with bad index - count:index" << _visualItems->
count() << viIndex;
516 if (item == _takeoffMissionItem) {
517 _takeoffMissionItem =
nullptr;
520 _deinitVisualItem(item);
523 if (removeSurveyStyle) {
525 bool foundSurvey =
false;
526 for (
int i=1; i<_visualItems->
count(); i++) {
535 bool rollSupported =
false;
536 bool pitchSupported =
false;
537 bool yawSupported =
false;
539 if (_controllerVehicle->
firmwarePlugin()->
hasGimbal(_controllerVehicle, rollSupported, pitchSupported, yawSupported) && pitchSupported) {
554 if (viIndex >= _visualItems->
count()) {
555 newVIIndex = _visualItems->
count() - 1;
557 newVIIndex = viIndex;
563 if (_visualItems->
count() == 1) {
573 _deinitAllVisualItems();
577 QTimer::singleShot(1000, oldItems, [oldItems] {
579 oldItems->deleteLater();
583 _settingsItem =
nullptr;
584 _takeoffMissionItem =
nullptr;
587 _visualItems = newItems;
588 if (_visualItems->
count() == 0) {
589 _addMissionSettings(_visualItems);
595 _addMissionSettings(_visualItems);
601 _setupNewVisualItems();
602 _initAllVisualItems();
604 _resetMissionFlightStatus();
611 QList<JsonParsing::KeyValidateInfo> rootKeyInfoList = {
612 { _jsonPlannedHomePositionKey, QJsonValue::Array,
true },
613 { _jsonItemsKey, QJsonValue::Array,
true },
614 { _jsonFirmwareTypeKey, QJsonValue::Double,
true },
615 { _jsonVehicleTypeKey, QJsonValue::Double,
false },
616 { _jsonCruiseSpeedKey, QJsonValue::Double,
false },
617 { _jsonHoverSpeedKey, QJsonValue::Double,
false },
618 { _jsonGlobalPlanAltitudeModeKey, QJsonValue::Double,
false },
626 qCDebug(MissionControllerLog) <<
"MissionController::_loadJsonMissionFileV2 itemCount:" << json[_jsonItemsKey].toArray().count();
631 MAV_AUTOPILOT planFileFirmwareType =
static_cast<MAV_AUTOPILOT
>(json[_jsonFirmwareTypeKey].toInt());
633 if (json.contains(_jsonVehicleTypeKey)) {
634 planFileVehicleType =
static_cast<MAV_TYPE
>(json[_jsonVehicleTypeKey].toInt());
639 appSettings->offlineEditingFirmwareClass()->setRawValue(
QGCMAVLink::firmwareClass(
static_cast<MAV_AUTOPILOT
>(json[_jsonFirmwareTypeKey].toInt())));
640 if (json.contains(_jsonVehicleTypeKey)) {
650 if (json.contains(_jsonCruiseSpeedKey)) {
651 appSettings->offlineEditingCruiseSpeed()->setRawValue(json[_jsonCruiseSpeedKey].toDouble());
653 if (json.contains(_jsonHoverSpeedKey)) {
654 appSettings->offlineEditingHoverSpeed()->setRawValue(json[_jsonHoverSpeedKey].toDouble());
656 if (json.contains(_jsonGlobalPlanAltitudeModeKey)) {
657 setGlobalAltitudeFrame(json[_jsonGlobalPlanAltitudeModeKey].toVariant().value<QGroundControlQmlGlobal::AltitudeFrame>());
660 QGeoCoordinate homeCoordinate;
667 qCDebug(MissionControllerLog) <<
"plannedHomePosition" << homeCoordinate;
671 int nextSequenceNumber = 1;
672 const QJsonArray rgMissionItems(json[_jsonItemsKey].toArray());
673 for (
int i=0; i<rgMissionItems.count(); i++) {
675 const QJsonValue& itemValue = rgMissionItems[i];
676 if (!itemValue.isObject()) {
677 errorString = tr(
"Mission item %1 is not an object").arg(i);
680 const QJsonObject itemObject = itemValue.toObject();
684 QList<JsonParsing::KeyValidateInfo> itemKeyInfoList = {
699 simpleItem->deleteLater();
700 simpleItem = takeoffItem;
702 qCDebug(MissionControllerLog) <<
"Loading simple item: nextSequenceNumber:command" << nextSequenceNumber << simpleItem->
command();
709 QList<JsonParsing::KeyValidateInfo> complexItemKeyInfoList = {
717 qCDebug(MissionControllerLog) <<
"Loading complex item type:" << complexItemType <<
"nextSequenceNumber:" << nextSequenceNumber;
720 errorString = tr(
"Unsupported complex item type: %1").arg(complexItemType);
723 if (!complexItem->
load(itemObject, nextSequenceNumber++,
errorString)) {
728 qCDebug(MissionControllerLog) <<
"Complex item load complete nextSequenceNumber:" << nextSequenceNumber;
731 errorString = tr(
"Unknown item type: %1").arg(itemType);
740 if (doJumpItem->
command() == MAV_CMD_DO_JUMP) {
754 errorString = tr(
"Could not find doJumpId: %1").arg(findDoJumpId);
766 bool firstItem =
true;
767 bool plannedHomePositionInFile =
false;
769 QString firstLine = stream.readLine();
770 const QStringList& version = firstLine.split(
" ");
772 bool versionOk =
false;
773 if (version.size() == 3 && version[0] ==
"QGC" && version[1] ==
"WPL") {
774 if (version[2] ==
"110") {
777 plannedHomePositionInFile =
true;
778 }
else if (version[2] ==
"120") {
781 plannedHomePositionInFile =
false;
788 while (!stream.atEnd()) {
790 if (item->
load(stream)) {
791 if (firstItem && plannedHomePositionInFile) {
804 errorString = tr(
"The mission file is corrupted.");
809 errorString = tr(
"The mission file is not compatible with this version of %1.").arg(QCoreApplication::applicationName());
813 if (!plannedHomePositionInFile) {
817 if (item && item->
command() == MAV_CMD_DO_JUMP) {
828 _setupNewVisualItems(loadedVisualItems);
832 _initAllVisualItems();
834 if (_visualItems->
count() > 1) {
844 QString errorMessage = tr(
"Mission: %1");
847 if (!_loadJsonMissionFileV2(json, loadedVisualItems, errorStr)) {
851 _initLoadedVisualItems(loadedVisualItems);
859 QString errorMessage = tr(
"Mission: %1");
860 QByteArray bytes = file.readAll();
861 QTextStream stream(bytes);
866 if (!_loadTextMissionFile(stream, loadedVisualItems, errorStr)) {
871 _initLoadedVisualItems(loadedVisualItems);
878 for (
int i=0; i<_visualItems->
count(); i++) {
896 qWarning() <<
"First item is not MissionSettingsItem";
899 QJsonValue coordinateValue;
901 json[_jsonPlannedHomePositionKey] = coordinateValue;
902 json[_jsonFirmwareTypeKey] = _controllerVehicle->
firmwareType();
903 json[_jsonVehicleTypeKey] = _controllerVehicle->
vehicleType();
906 json[_jsonGlobalPlanAltitudeModeKey] = _globalAltFrame;
910 QJsonArray rgJsonMissionItems;
911 for (
int i=0; i<_visualItems->
count(); i++) {
914 visualItem->
save(rgJsonMissionItems);
919 QList<MissionItem*> rgMissionItems;
921 if (_convertToMissionItems(_visualItems, rgMissionItems,
this )) {
922 QJsonObject saveObject;
923 MissionItem* missionItem = rgMissionItems[rgMissionItems.count() - 1];
924 missionItem->
save(saveObject);
925 rgJsonMissionItems.append(saveObject);
927 for (
int i=0; i<rgMissionItems.count(); i++) {
928 rgMissionItems[i]->deleteLater();
932 json[_jsonItemsKey] = rgJsonMissionItems;
937 if (pair.second->isTakeoffItem()) {
940 if (pair.second->isLandCommand()) {
950 bool takeoffStraightUp = pair.second->isTakeoffItem() && !_controllerVehicle->
fixedWing();
952 QGeoCoordinate coord1 = pair.first->exitCoordinate();
953 QGeoCoordinate coord2 = pair.second->entryCoordinate();
954 double coord2AMSLAlt = pair.second->amslEntryAlt();
955 double coord1AMSLAlt = takeoffStraightUp ? coord2AMSLAlt : pair.first->amslExitAlt();
961 if (takeoffStraightUp) {
986 if (prevItemPairHashTable.contains(pair) &&
987 prevItemPairHashTable[pair]->segmentType() ==
segmentTypeForPair(pair, mavlinkTerrainFrame)) {
989 _flightPathSegmentHashTable[pair] = segment = prevItemPairHashTable.take(pair);
991 segment = _createFlightPathSegmentWorker(pair, mavlinkTerrainFrame);
992 _flightPathSegmentHashTable[pair] = segment;
995 _simpleFlightPathSegments.
append(segment);
1000void MissionController::_recalcFlightPathSegments(
void)
1003 int segmentCount = 0;
1004 bool firstCoordinateNotFound =
true;
1006 bool linkEndToHome =
false;
1007 bool linkStartToHome = _controllerVehicle->
rover() ? true :
false;
1008 bool foundRTL =
false;
1009 bool homePositionValid = _settingsItem->
coordinate().isValid();
1010 bool roiActive =
false;
1011 bool previousItemIsIncomplete =
false;
1015 qCDebug(MissionControllerLog) <<
"_recalcFlightPathSegments homePositionValid" << homePositionValid;
1019 _missionStartsInVTOLMulticopterMode =
false;
1020 _flightPathSegmentHashTable.clear();
1025 _simpleFlightPathSegments.
clear();
1026 _directionArrows.
clear();
1033 for (
int i=1; i<_visualItems->
count(); i++) {
1034 qobject_cast<VisualMissionItem*>(_visualItems->
get(i))->clearSimpleFlighPathSegment();
1038 for (
int i=1; i<_visualItems->
count(); i++) {
1047 if (_isROICancelItem(simpleItem)) {
1051 if (_isROIBeginItem(simpleItem)) {
1059 case MAV_CMD_NAV_TAKEOFF:
1060 if (!linkEndToHome && firstCoordinateNotFound) {
1061 _missionStartsInVTOLMulticopterMode =
1063 linkStartToHome =
true;
1066 case MAV_CMD_NAV_VTOL_TAKEOFF:
1067 if (!linkEndToHome && firstCoordinateNotFound) {
1068 _missionStartsInVTOLMulticopterMode =
true;
1069 linkStartToHome =
true;
1072 case MAV_CMD_NAV_RETURN_TO_LAUNCH:
1073 linkEndToHome =
true;
1088 lastFlyThroughVI = visualItem;
1098 previousItemIsIncomplete =
true;
1099 }
else if (previousItemIsIncomplete) {
1101 previousItemIsIncomplete =
false;
1102 firstCoordinateNotFound =
false;
1103 lastFlyThroughVI = visualItem;
1105 if (lastFlyThroughVI != _settingsItem || (homePositionValid && linkStartToHome)) {
1106 bool addDirectionArrow =
false;
1112 addDirectionArrow =
true;
1113 }
else if (segmentCount > 5) {
1115 addDirectionArrow =
true;
1120 lastSegmentVisualItemPair =
VisualItemPair(lastFlyThroughVI, visualItem);
1122 bool mavlinkTerrainFrame = simpleItem ? simpleItem->
missionItem().
frame() == MAV_FRAME_GLOBAL_TERRAIN_ALT :
false;
1123 FlightPathSegment* segment = _addFlightPathSegment(oldSegmentTable, lastSegmentVisualItemPair, mavlinkTerrainFrame);
1125 if (addDirectionArrow) {
1126 _directionArrows.
append(segment);
1129 const bool legStartsAtCoordinateItem = lastFlyThroughVI != _settingsItem &&
1133 newSplitSegment = segment;
1137 firstCoordinateNotFound =
false;
1138 lastFlyThroughVI = visualItem;
1143 if (linkEndToHome && lastFlyThroughVI != _settingsItem && homePositionValid) {
1144 lastSegmentVisualItemPair =
VisualItemPair(lastFlyThroughVI, _settingsItem);
1145 FlightPathSegment* segment = _addFlightPathSegment(oldSegmentTable, lastSegmentVisualItemPair,
false );
1151 if (lastSegmentVisualItemPair.first) {
1157 if (_flightPathSegmentHashTable.contains(lastSegmentVisualItemPair)) {
1159 coordVector = _flightPathSegmentHashTable[lastSegmentVisualItemPair];
1160 }
else if (oldSegmentTable.contains(lastSegmentVisualItemPair)) {
1162 _flightPathSegmentHashTable[lastSegmentVisualItemPair] = coordVector = oldSegmentTable.take(lastSegmentVisualItemPair);
1167 lastSegmentVisualItemPair.first->isSimpleItem() ? lastSegmentVisualItemPair.first->entryCoordinate() : lastSegmentVisualItemPair.first->exitCoordinate(),
1168 lastSegmentVisualItemPair.first->isSimpleItem() ? lastSegmentVisualItemPair.first->amslEntryAlt() : lastSegmentVisualItemPair.first->amslExitAlt(),
1169 lastSegmentVisualItemPair.second->entryCoordinate(),
1170 lastSegmentVisualItemPair.second->amslEntryAlt(),
1173 _flightPathSegmentHashTable[lastSegmentVisualItemPair] = coordVector;
1176 _directionArrows.
append(coordVector);
1183 const bool signalSplitSegmentChanged = newSplitSegment != _splitSegment;
1184 _splitSegment = newSplitSegment;
1187 qDeleteAll(oldSegmentTable);
1192 if (signalSplitSegmentChanged) {
1193 qCDebug(MissionControllerLog) <<
"splitSegmentSet:" << (_splitSegment !=
nullptr);
1198void MissionController::_recalcMissionFlightStatus()
1200 if (!_visualItems->
count()) {
1204 qCDebug(MissionControllerLog) <<
"_recalcMissionFlightStatus";
1206 _flightStatusCalc.
recalc(
1207 _visualItems, _settingsItem, _controllerVehicle, _managerVehicle, _appSettings, _planViewSettings,
1208 _missionStartsInVTOLMulticopterMode);
1209 _missionFlightStatus = _flightStatusCalc.
status();
1232void MissionController::_recalcSequence(
void)
1234 if (_inRecalcSequence) {
1241 _inRecalcSequence =
true;
1242 int sequenceNumber = 0;
1243 for (
int i=0; i<_visualItems->
count(); i++) {
1248 _inRecalcSequence =
false;
1252void MissionController::_recalcChildItems(
void)
1258 for (
int i=1; i<_visualItems->
count(); i++) {
1267 currentParentItem = item;
1278void MissionController::_setupTreeModel(
void)
1282 _visualItemsTree.
clear();
1285 _planFileGroupNode.setObjectName(tr(
"Plan Info"));
1286 _visualItemsTree.
appendItem(&_planFileGroupNode, QModelIndex(), QStringLiteral(
"planFileGroup"));
1288 _planFileInfoMarker.setObjectName(QStringLiteral(
"planFileInfo"));
1289 _visualItemsTree.
appendItem(&_planFileInfoMarker,
1290 _visualItemsTree.
indexForObject(&_planFileGroupNode), QStringLiteral(
"planFileInfo"));
1293 _defaultsGroupNode.setObjectName(tr(
"Defaults"));
1294 _visualItemsTree.
appendItem(&_defaultsGroupNode, QModelIndex(), QStringLiteral(
"defaultsGroup"));
1296 _defaultsInfoMarker.setObjectName(QStringLiteral(
"defaultsInfo"));
1297 _visualItemsTree.
appendItem(&_defaultsInfoMarker,
1298 _visualItemsTree.
indexForObject(&_defaultsGroupNode), QStringLiteral(
"defaultsInfo"));
1301 _missionItemsGroupNode.setObjectName(tr(
"Mission Items"));
1302 _visualItemsTree.
appendItem(&_missionItemsGroupNode, QModelIndex(), QStringLiteral(
"missionGroup"));
1305 _fenceGroupNode.setObjectName(tr(
"GeoFence"));
1306 _visualItemsTree.
appendItem(&_fenceGroupNode, QModelIndex(), QStringLiteral(
"fenceGroup"));
1309 _fenceEditorMarker.setObjectName(QStringLiteral(
"fenceEditor"));
1310 _visualItemsTree.
appendItem(&_fenceEditorMarker,
1311 _visualItemsTree.
indexForObject(&_fenceGroupNode), QStringLiteral(
"fenceEditor"));
1314 _rallyGroupNode.setObjectName(tr(
"Rally Points"));
1315 _visualItemsTree.
appendItem(&_rallyGroupNode, QModelIndex(), QStringLiteral(
"rallyGroup"));
1318 _rallyHeaderMarker.setObjectName(QStringLiteral(
"rallyHeader"));
1319 _visualItemsTree.
appendItem(&_rallyHeaderMarker,
1320 _visualItemsTree.
indexForObject(&_rallyGroupNode), QStringLiteral(
"rallyHeader"));
1323 _transformGroupNode.setObjectName(tr(
"Transform"));
1324 _visualItemsTree.
appendItem(&_transformGroupNode, QModelIndex(), QStringLiteral(
"transformGroup"));
1327 _transformEditorMarker.setObjectName(QStringLiteral(
"transformEditor"));
1328 _visualItemsTree.
appendItem(&_transformEditorMarker,
1329 _visualItemsTree.
indexForObject(&_transformGroupNode), QStringLiteral(
"transformEditor"));
1334 _planFileGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_planFileGroupNode));
1335 _defaultsGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_defaultsGroupNode));
1336 _missionGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_missionItemsGroupNode));
1337 _fenceGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_fenceGroupNode));
1338 _rallyGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_rallyGroupNode));
1339 _transformGroupIndex = QPersistentModelIndex(_visualItemsTree.
indexForObject(&_transformGroupNode));
1346void MissionController::_syncTreeMissionItemsInserted(
const QModelIndex& parent,
int first,
int last)
1349 for (
int i = first; i <= last; i++) {
1352 _visualItemsTree.
insertItem(i, item, _missionGroupIndex, QStringLiteral(
"missionItem"));
1357void MissionController::_syncTreeMissionItemsAboutToBeRemoved(
const QModelIndex& parent,
int first,
int last)
1361 for (
int i = last; i >= first; i--) {
1362 _visualItemsTree.
removeAt(_missionGroupIndex, i);
1366void MissionController::_syncTreeMissionItemsReset(
void)
1373 for (
int i = 0; i < _visualItems->
count(); i++) {
1376 _visualItemsTree.
appendItem(item, _missionGroupIndex, QStringLiteral(
"missionItem"));
1386void MissionController::_syncTreeRallyPointsInserted(
const QModelIndex& parent,
int first,
int last)
1390 if (!rallyController)
return;
1393 if (first == 0 && _visualItemsTree.
rowCount(_rallyGroupIndex) == 1) {
1394 const QModelIndex child = _visualItemsTree.
index(0, 0, _rallyGroupIndex);
1400 auto* pts = rallyController->points();
1401 for (
int i = first; i <= last; i++) {
1402 _visualItemsTree.
insertItem(i, (*pts)[i], _rallyGroupIndex, QStringLiteral(
"rallyItem"));
1406void MissionController::_syncTreeRallyPointsAboutToBeRemoved(
const QModelIndex& parent,
int first,
int last)
1409 for (
int i = last; i >= first; i--) {
1410 _visualItemsTree.
removeAt(_rallyGroupIndex, i);
1414void MissionController::_syncTreeRallyPointsRemoved(
const QModelIndex& parent,
int first,
int last)
1422 if (rallyController && rallyController->points()->count() == 0) {
1423 _rallyHeaderMarker.setObjectName(QStringLiteral(
"rallyHeader"));
1424 _visualItemsTree.
appendItem(&_rallyHeaderMarker, _rallyGroupIndex, QStringLiteral(
"rallyHeader"));
1428void MissionController::_syncTreeRallyPointsReset(
void)
1436 if (rallyController && rallyController->points()->count() > 0) {
1437 auto* pts = rallyController->
points();
1438 for (
int i = 0; i < pts->count(); i++) {
1439 _visualItemsTree.
appendItem((*pts)[i], _rallyGroupIndex, QStringLiteral(
"rallyItem"));
1442 _rallyHeaderMarker.setObjectName(QStringLiteral(
"rallyHeader"));
1443 _visualItemsTree.
appendItem(&_rallyHeaderMarker, _rallyGroupIndex, QStringLiteral(
"rallyHeader"));
1447void MissionController::_setPlannedHomePositionFromFirstCoordinate(
const QGeoCoordinate& clickCoordinate)
1449 bool foundFirstCoordinate =
false;
1450 QGeoCoordinate firstCoordinate;
1457 for (
int i=1; i<_visualItems->
count(); i++) {
1461 foundFirstCoordinate =
true;
1468 if (!foundFirstCoordinate) {
1469 firstCoordinate = clickCoordinate;
1472 if (firstCoordinate.isValid()) {
1473 QGeoCoordinate plannedHomeCoord = firstCoordinate.atDistanceAndAzimuth(30, 0);
1474 plannedHomeCoord.setAltitude(0);
1479void MissionController::_recalcAllWithCoordinate(
const QGeoCoordinate& coordinate)
1482 _setPlannedHomePositionFromFirstCoordinate(coordinate);
1485 _recalcChildItems();
1490void MissionController::_recalcAll(
void)
1492 QGeoCoordinate emptyCoord;
1493 _recalcAllWithCoordinate(emptyCoord);
1497void MissionController::_initAllVisualItems(
void)
1501 if (!_settingsItem) {
1502 _settingsItem = qobject_cast<MissionSettingsItem*>(_visualItems->
get(0));
1503 if (!_settingsItem) {
1504 qWarning() <<
"First item not MissionSettingsItem";
1513 for (
int i=0; i<_visualItems->
count(); i++) {
1515 _initVisualItem(item);
1519 _takeoffMissionItem = takeoffItem;
1529 connect(_visualItems, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeMissionItemsInserted);
1530 connect(_visualItems, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeMissionItemsAboutToBeRemoved);
1531 connect(_visualItems, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeMissionItemsReset);
1534 _syncTreeMissionItemsReset();
1538 if (rallyController) {
1539 auto* pts = rallyController->
points();
1540 connect(pts, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeRallyPointsInserted);
1541 connect(pts, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeRallyPointsAboutToBeRemoved);
1542 connect(pts, &QAbstractItemModel::rowsRemoved,
this, &MissionController::_syncTreeRallyPointsRemoved);
1543 connect(pts, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeRallyPointsReset);
1546 _syncTreeRallyPointsReset();
1561void MissionController::_deinitAllVisualItems(
void)
1567 for (
int i=0; i<_visualItems->
count(); i++) {
1568 _deinitVisualItem(qobject_cast<VisualMissionItem*>(_visualItems->
get(i)));
1575 disconnect(_visualItems, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeMissionItemsInserted);
1576 disconnect(_visualItems, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeMissionItemsAboutToBeRemoved);
1577 disconnect(_visualItems, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeMissionItemsReset);
1581 if (rallyController) {
1582 auto* pts = rallyController->
points();
1583 disconnect(pts, &QAbstractItemModel::rowsInserted,
this, &MissionController::_syncTreeRallyPointsInserted);
1584 disconnect(pts, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &MissionController::_syncTreeRallyPointsAboutToBeRemoved);
1585 disconnect(pts, &QAbstractItemModel::rowsRemoved,
this, &MissionController::_syncTreeRallyPointsRemoved);
1586 disconnect(pts, &QAbstractItemModel::modelReset,
this, &MissionController::_syncTreeRallyPointsReset);
1613 qWarning() <<
"isSimpleItem == true, yet not SimpleMissionItem";
1624 qWarning() <<
"ComplexMissionItem not found";
1634 disconnect(visualItem,
nullptr,
this,
nullptr);
1637void MissionController::_itemCommandChanged(
void)
1639 _recalcChildItems();
1643void MissionController::_managerVehicleChanged(
Vehicle* managerVehicle)
1645 if (_managerVehicle) {
1646 _missionManager->disconnect(
this);
1647 _managerVehicle->disconnect(
this);
1648 _managerVehicle =
nullptr;
1649 _missionManager =
nullptr;
1652 _managerVehicle = managerVehicle;
1653 if (!_managerVehicle) {
1654 qWarning() <<
"MissionController::managerVehicleChanged managerVehicle=NULL";
1676void MissionController::_inProgressChanged(
bool inProgress)
1684 double foundAltitude = 0;
1687 if (newIndex > _visualItems->
count()) {
1692 for (
int i=newIndex; i>0; i--) {
1709 *prevAltitude = foundAltitude;
1710 *prevAltitudeMode = foundAltFrame;
1716double MissionController::_normalizeLat(
double lat)
1722double MissionController::_normalizeLon(
double lon)
1731 qCDebug(MissionControllerLog) <<
"_addMissionSettings";
1737 _settingsItem = settingsItem;
1740 return settingsItem;
1746 int resumeIndex = 0;
1770 return currentIndex;
1774void MissionController::_currentMissionIndexChanged(
int sequenceNumber)
1781 for (
int i=0; i<_visualItems->
count(); i++) {
1796 return _visualItems ? _visualItems->
dirty() :
false;
1815 while (scanIndex < visualItems->count()) {
1818 qCDebug(MissionControllerLog) <<
"MissionController::_scanForAdditionalSettings count:scanIndex" <<
visualItems->
count() << scanIndex;
1842 return _visualItems ? _visualItems->
count() > 1 :
false;
1848 qCCritical(MissionControllerLog) <<
"MissionControllerLog::removeAllFromVehicle called while offline";
1850 qCCritical(MissionControllerLog) <<
"MissionControllerLog::removeAllFromVehicle called while syncInProgress";
1852 _itemsRequested =
true;
1872 if (_settingsItem) {
1875 return QGeoCoordinate();
1881 return _settingsItem && _settingsItem->
coordinate().isValid();
1886 if (_settingsItem) {
1893 double defaultAltitude = _appSettings->defaultMissionItemAltitude()->rawValue().toDouble();
1895 for (
int i=1; i<_visualItems->
count(); i++) {
1901void MissionController::_progressPctChanged(
double progressPct)
1909void MissionController::_visualItemsDirtyChanged(
bool dirty)
1917 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle _flyView" <<
_flyView;
1919 qCCritical(MissionControllerLog) <<
"MissionController::showPlanFromManagerVehicle called while offline";
1924 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal";
1928 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle: syncInProgress wait for signal";
1932 qCDebug(MissionControllerLog) <<
"showPlanFromManagerVehicle: sync complete simulate signal";
1933 _itemsRequested =
true;
1934 _newMissionItemsAvailableFromVehicle(
false );
1940void MissionController::_managerSendComplete(
bool error)
1948void MissionController::_managerRemoveAllComplete(
bool error)
1958 return simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI_LOCATION ||
1959 simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI_WPNEXT_OFFSET ||
1960 (simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI &&
1966 return simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI_NONE ||
1967 (simpleItem->
mavCommand() == MAV_CMD_DO_SET_ROI &&
1973 if (_visualItems && (force || sequenceNumber != _currentPlanViewSeqNum)) {
1974 qCDebug(MissionControllerLog) <<
"setCurrentPlanViewSeqNum";
1975 bool foundLand =
false;
1976 bool onlyInsertTakeoffValid =
false;
1977 int takeoffSeqNum = -1;
1978 int landSeqNum = -1;
1979 int lastFlyThroughSeqNum = -1;
1981 _splitSegment =
nullptr;
1982 _currentPlanViewItem =
nullptr;
1983 _currentPlanViewSeqNum = -1;
1984 _currentPlanViewVIIndex = -1;
1985 _isInsertTakeoffValid =
true;
1986 _isInsertLandValid =
true;
1987 _isInsertROIValid =
false;
1988 _isROIActive =
false;
1989 _isROIBeginCurrentItem =
false;
1990 _flyThroughCommandsAllowed =
true;
1991 _previousCoordinate = QGeoCoordinate();
1993 bool noItemsAddedYet = _visualItems->
count() == 1;
1995 onlyInsertTakeoffValid =
true;
1998 for (
int viIndex=0; viIndex<_visualItems->
count(); viIndex++) {
2003 if (sequenceNumber != 0 && currentSeqNumber <= sequenceNumber) {
2006 _isInsertTakeoffValid =
false;
2010 if (qobject_cast<TakeoffMissionItem*>(pVI)) {
2011 takeoffSeqNum = currentSeqNumber;
2012 _isInsertTakeoffValid =
false;
2018 case MAV_CMD_NAV_LAND:
2019 case MAV_CMD_NAV_VTOL_LAND:
2020 case MAV_CMD_DO_LAND_START:
2021 case MAV_CMD_NAV_RETURN_TO_LAUNCH:
2023 landSeqNum = currentSeqNumber;
2032 landSeqNum = currentSeqNumber;
2039 if (currentSeqNumber < sequenceNumber && simpleItem->specifiesCoordinate() && !simpleItem->
isStandaloneCoordinate()) {
2040 _previousCoordinate = simpleItem->
coordinate();
2044 if (currentSeqNumber <= sequenceNumber) {
2046 if (_isROICancelItem(simpleItem)) {
2047 _isROIActive =
false;
2050 if (_isROIBeginItem(simpleItem)) {
2051 _isROIActive =
true;
2055 if (currentSeqNumber == sequenceNumber && _isROIBeginItem(simpleItem)) {
2056 _isROIBeginCurrentItem =
true;
2063 lastFlyThroughSeqNum = currentSeqNumber;
2067 if (currentSeqNumber == sequenceNumber) {
2071 _currentPlanViewItem = pVI;
2072 _currentPlanViewSeqNum = sequenceNumber;
2073 _currentPlanViewVIIndex = viIndex;
2078 for (
int j=viIndex-1; j>0; j--) {
2082 _splitSegment = _flightPathSegmentHashTable.value(
VisualItemPair(pPrev, pVI),
nullptr);
2097 if (takeoffSeqNum != -1) {
2099 if (sequenceNumber < takeoffSeqNum) {
2101 _isInsertLandValid =
false;
2103 _flyThroughCommandsAllowed =
false;
2107 if (lastFlyThroughSeqNum != -1) {
2109 if (sequenceNumber < lastFlyThroughSeqNum) {
2110 _isInsertLandValid =
false;
2115 _isInsertLandValid =
false;
2116 if (sequenceNumber >= landSeqNum) {
2118 _flyThroughCommandsAllowed =
false;
2122 if (_hasLandItem != foundLand) {
2124 _hasLandItem = foundLand;
2129 _isInsertLandValid = _isInsertLandValid && !onlyInsertTakeoffValid;
2130 _flyThroughCommandsAllowed = _flyThroughCommandsAllowed && !onlyInsertTakeoffValid;
2134 _isInsertTakeoffValid = _isInsertTakeoffValid && homePosSet;
2135 _isInsertLandValid = _isInsertLandValid && homePosSet;
2136 _flyThroughCommandsAllowed = _flyThroughCommandsAllowed && homePosSet;
2137 _isInsertROIValid = homePosSet && !onlyInsertTakeoffValid;
2149 bool repositionTakeoffItems,
2150 bool repositionLandingItems)
2152 if (!newHome.isValid()) {
2153 qCWarning(MissionControllerLog) <<
"Cannot reposition mission to an invalid coordinate";
2157 if (!_settingsItem || !_settingsItem->
coordinate().isValid()) {
2158 qCWarning(MissionControllerLog) <<
"Cannot reposition mission while home is invalid";
2162 const QGeoCoordinate oldHome = _settingsItem->
coordinate();
2164 for (
int i = 0; i < _visualItems->
count(); ++i) {
2165 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2175 const QGeoCoordinate oldCoord = item->
coordinate();
2176 if (!oldCoord.isValid()) {
2180 const double distanceMeters = oldHome.distanceTo(oldCoord);
2181 const double azimuthDegrees = oldHome.azimuthTo(oldCoord);
2183 QGeoCoordinate newCoord = newHome.atDistanceAndAzimuth(distanceMeters, azimuthDegrees);
2193 bool offsetTakeoffItems,
2194 bool offsetLandingItems)
2196 if (!qFuzzyIsNull(eastMeters) || !qFuzzyIsNull(northMeters)) {
2197 const double distanceMeters = qSqrt(eastMeters * eastMeters + northMeters * northMeters);
2198 double azimuthDegrees = 0.0;
2199 if (!qFuzzyIsNull(distanceMeters)) {
2200 const double azimuthRadians = qAtan2(eastMeters, northMeters);
2201 azimuthDegrees = qRadiansToDegrees(azimuthRadians);
2204 for (
int i = 0; i < _visualItems->
count(); ++i) {
2205 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2215 const QGeoCoordinate oldCoord = item->
coordinate();
2216 if (!oldCoord.isValid()) {
2220 item->
setCoordinate(oldCoord.atDistanceAndAzimuth(distanceMeters, azimuthDegrees));
2226 if (!qFuzzyIsNull(upMeters)) {
2227 for (
int i = 0; i < _visualItems->
count(); ++i) {
2228 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2229 if (!item || item == _settingsItem) {
2252 bool rotateTakeoffItems,
2253 bool rotateLandingItems)
2255 if (qFuzzyIsNull(degreesCW)) {
2259 if (!_settingsItem || !_settingsItem->
coordinate().isValid()) {
2260 qCWarning(MissionControllerLog) <<
"Cannot rotate mission while home is invalid";
2264 const QGeoCoordinate home = _settingsItem->
coordinate();
2266 for (
int i = 0; i < _visualItems->
count(); ++i) {
2267 auto* item = qobject_cast<VisualMissionItem*>(_visualItems->
get(i));
2277 const QGeoCoordinate oldCoord = item->
coordinate();
2278 if (!oldCoord.isValid()) {
2282 const double distanceMeters = home.distanceTo(oldCoord);
2283 if (qFuzzyIsNull(distanceMeters)) {
2286 const double azimuthDegrees = home.azimuthTo(oldCoord);
2288 QGeoCoordinate newCoord = home.atDistanceAndAzimuth(distanceMeters, azimuthDegrees + degreesCW);
2295void MissionController::_updateTimeout()
2297 QGeoCoordinate firstCoordinate;
2301 double south = 180.0;
2303 double west = 360.0;
2306 for (
int i = 1; i < _visualItems->
count(); i++) {
2311 switch(pSimpleItem->
command()) {
2312 case MAV_CMD_NAV_TAKEOFF:
2313 case MAV_CMD_NAV_WAYPOINT:
2314 case MAV_CMD_NAV_LAND:
2320 if((MAV_CMD)pSimpleItem->
command() == MAV_CMD_NAV_TAKEOFF) {
2323 minAlt = maxAlt = alt;
2324 }
else if(!firstCoordinate.isValid()) {
2327 double lat = pSimpleItem->
coordinate().latitude() + 90.0;
2328 double lon = pSimpleItem->
coordinate().longitude() + 180.0;
2329 north = fmax(north, lat);
2330 south = fmin(south, lat);
2331 east = fmax(east, lon);
2332 west = fmin(west, lon);
2333 minAlt = fmin(minAlt, alt);
2334 maxAlt = fmax(maxAlt, alt);
2346 if(!firstCoordinate.isValid() && pComplexItem->
entryCoordinate().isValid()) {
2349 north = fmax(north, bc.
pointNW.latitude() + 90.0);
2350 south = fmin(south, bc.
pointSE.latitude() + 90.0);
2351 east = fmax(east, bc.
pointNW.longitude() + 180.0);
2352 west = fmin(west, bc.
pointSE.longitude() + 180.0);
2353 minAlt = fmin(minAlt, bc.
pointNW.altitude());
2354 maxAlt = fmax(maxAlt, bc.
pointSE.altitude());
2361 if(firstCoordinate.isValid()) {
2369 QGeoCoordinate(north - 90.0, west - 180.0, minAlt),
2370 QGeoCoordinate(south - 90.0, east - 180.0, maxAlt));
2371 if(_travelBoundingCube != boundingCube || _takeoffCoordinate !=
takeoffCoordinate) {
2373 _travelBoundingCube = boundingCube;
2375 qCDebug(MissionControllerLog) <<
"Bounding cube:" << _travelBoundingCube.
pointNW << _travelBoundingCube.
pointSE;
2379void MissionController::_complexBoundingBoxChanged()
2385 const int count = _visualItems->
count();
2387 for (
int i = 0; i < count; i++) {
2388 QObject *obj = _visualItems->
get(i);
2392 return landingItem == item;
2401 return _visualItems->
count() <= 1;
2404void MissionController::_recalcPlanViewState(
void)
2409void MissionController::_allItemsRemoved(
void)
2416void MissionController::_firstItemAdded(
void)
2439 return _globalAltFrame;
2447 return _globalAltFrame;
2453 if (_globalAltFrame != altFrame) {
2454 _globalAltFrame = altFrame;
#define UPDATE_TIMEOUT
How often we check for bounding box changes.
static FlightPathSegment::SegmentType segmentTypeForPair(const VisualItemPair &pair, bool mavlinkTerrainFrame)
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
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)
Q_INVOKABLE VisualMissionItem * insertVTOLMulticopterTakeoffItem(QGeoCoordinate coordinate, int visualItemIndex, bool makeCurrentItem=false)
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)
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 missionStartsInVTOLMulticopterMode)
void reset(Vehicle *controllerVehicle, Vehicle *managerVehicle, bool missionStartsInVTOLMulticopterMode)
Resets the flight status fields to defaults based on vehicle properties.
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)
void altitudeFrameChanged(void)
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)
static bool isVTOLMulticopterTakeoff(Vehicle *vehicle, 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.
GPSCommandSequence::Command command(QByteArrayView body, GPSTextMatcher reply, std::chrono::milliseconds timeout)
body labelled by its text, framed as a sentence, and completed by reply within timeout.
int batteriesRequired
-1 for not supported
double maxTelemetryDistance
int batteryChangePoint
-1 for not supported, 0 for not needed
static constexpr VehicleClass_t VehicleClassGeneric