diff --git a/src/MissionManager/CorridorScanComplexItem.cc b/src/MissionManager/CorridorScanComplexItem.cc index 2a93b928bd2eb8bc704f2aa1cd7979e0281fce4c..c7c23303d8fc7c02c69a67a422e629e6c409fd81 100644 --- a/src/MissionManager/CorridorScanComplexItem.cc +++ b/src/MissionManager/CorridorScanComplexItem.cc @@ -23,7 +23,7 @@ QGC_LOGGING_CATEGORY(CorridorScanComplexItemLog, "CorridorScanComplexItemLog") const char* CorridorScanComplexItem::settingsGroup = "CorridorScan"; const char* CorridorScanComplexItem::corridorWidthName = "CorridorWidth"; -const char* CorridorScanComplexItem::_entryPointName = "EntryPoint"; +const char* CorridorScanComplexItem::_jsonEntryPointKey = "EntryPoint"; const char* CorridorScanComplexItem::jsonComplexItemTypeValue = "CorridorScan"; @@ -77,16 +77,17 @@ int CorridorScanComplexItem::lastSequenceNumber(void) const return _sequenceNumber + itemCount - 1; } -void CorridorScanComplexItem::save(QJsonArray& missionItems) +void CorridorScanComplexItem::save(QJsonArray& planItems) { QJsonObject saveObject; - saveObject[JsonHelper::jsonVersionKey] = 1; + _save(saveObject); + + saveObject[JsonHelper::jsonVersionKey] = 2; saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue; saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue; saveObject[corridorWidthName] = _corridorWidthFact.rawValue().toDouble(); - saveObject[turnAroundDistanceName] = _turnAroundDistanceFact.rawValue().toDouble(); - saveObject[_entryPointName] = _entryPoint; + saveObject[_jsonEntryPointKey] = _entryPoint; QJsonObject cameraCalcObject; _cameraCalc.save(cameraCalcObject); @@ -94,28 +95,29 @@ void CorridorScanComplexItem::save(QJsonArray& missionItems) _corridorPolyline.saveToJson(saveObject); - _save(saveObject); - - missionItems.append(saveObject); + planItems.append(saveObject); } bool CorridorScanComplexItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString) { + // We don't recalc while loading since all the information we need is specified in the file + _ignoreRecalc = true; + QList keyInfoList = { { JsonHelper::jsonVersionKey, QJsonValue::Double, true }, { VisualMissionItem::jsonTypeKey, QJsonValue::String, true }, { ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true }, { corridorWidthName, QJsonValue::Double, true }, - { turnAroundDistanceName, QJsonValue::Double, true }, - { _entryPointName, QJsonValue::Double, true }, + { _jsonEntryPointKey, QJsonValue::Double, true }, { QGCMapPolyline::jsonPolylineKey, QJsonValue::Array, true }, - { _jsonCameraCalcKey, QJsonValue::Object, true }, }; if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) { + _ignoreRecalc = false; return false; } if (!_corridorPolyline.loadFromJson(complexObject, true, errorString)) { + _ignoreRecalc = false; return false; } @@ -123,27 +125,32 @@ bool CorridorScanComplexItem::load(const QJsonObject& complexObject, int sequenc QString complexType = complexObject[ComplexMissionItem::jsonComplexItemTypeKey].toString(); if (itemType != VisualMissionItem::jsonTypeComplexItemValue || complexType != jsonComplexItemTypeValue) { errorString = tr("%1 does not support loading this complex mission item type: %2:%3").arg(qgcApp()->applicationName()).arg(itemType).arg(complexType); + _ignoreRecalc = false; return false; } int version = complexObject[JsonHelper::jsonVersionKey].toInt(); - if (version != 1) { + if (version != 2) { errorString = tr("%1 complex item version %2 not supported").arg(jsonComplexItemTypeValue).arg(version); + _ignoreRecalc = false; return false; } setSequenceNumber(sequenceNumber); if (!_load(complexObject, errorString)) { + _ignoreRecalc = false; return false; } _corridorWidthFact.setRawValue (complexObject[corridorWidthName].toDouble()); - _entryPoint = complexObject[_entryPointName].toInt(); + _entryPoint = complexObject[_jsonEntryPointKey].toInt(); _rebuildCorridor(); + _ignoreRecalc = false; + return true; } @@ -159,8 +166,23 @@ int CorridorScanComplexItem::_transectCount(void) const return fullWidth > 0.0 ? qCeil(fullWidth / transectSpacing) : 1; } -void CorridorScanComplexItem::appendMissionItems(QList& items, QObject* missionItemParent) +void CorridorScanComplexItem::_appendLoadedMissionItems(QList& items, QObject* missionItemParent) +{ + qCDebug(CorridorScanComplexItemLog) << "_appendLoadedMissionItems"; + + int seqNum = _sequenceNumber; + + foreach (const MissionItem* loadedMissionItem, _loadedMissionItems) { + MissionItem* item = new MissionItem(*loadedMissionItem, missionItemParent); + item->setSequenceNumber(seqNum++); + items.append(item); + } +} + +void CorridorScanComplexItem::_buildAndAppendMissionItems(QList& items, QObject* missionItemParent) { + qCDebug(CorridorScanComplexItemLog) << "_buildAndAppendMissionItems"; + int seqNum = _sequenceNumber; int pointIndex = 0; bool imagesEverywhere = _cameraTriggerInTurnAroundFact.rawValue().toBool(); @@ -279,6 +301,17 @@ void CorridorScanComplexItem::appendMissionItems(QList& items, QOb } } +void CorridorScanComplexItem::appendMissionItems(QList& items, QObject* missionItemParent) +{ + if (_loadedMissionItems.count()) { + // We have mission items from the loaded plan, use those + _appendLoadedMissionItems(items, missionItemParent); + } else { + // Build the mission items on the fly + _buildAndAppendMissionItems(items, missionItemParent); + } +} + void CorridorScanComplexItem::applyNewAltitude(double newAltitude) { _cameraCalc.valueSetIsDistance()->setRawValue(true); @@ -324,10 +357,20 @@ void CorridorScanComplexItem::_rebuildCorridorPolygon(void) } } -void CorridorScanComplexItem::_rebuildTransects(void) +void CorridorScanComplexItem::_rebuildTransectsPhase1(void) { + if (_ignoreRecalc) { + return; + } + + // If the transects are getting rebuilt then any previsouly loaded mission items are now invalid + if (_loadedMissionItemsParent) { + _loadedMissionItems.clear(); + _loadedMissionItemsParent->deleteLater(); + _loadedMissionItemsParent = NULL; + } + _transectPoints.clear(); - _cameraShots = 0; double transectSpacing = _cameraCalc.adjustedFootprintSide()->rawValue().toDouble(); double fullWidth = _corridorWidthFact.rawValue().toDouble(); @@ -336,13 +379,9 @@ void CorridorScanComplexItem::_rebuildTransects(void) double normalizedTransectPosition = transectSpacing / 2.0; if (_corridorPolyline.count() >= 2) { - int singleTransectImageCount = qCeil(_corridorPolyline.length() / _cameraCalc.adjustedFootprintFrontal()->rawValue().toDouble()); - // First build up the transects all going the same direction QList> transects; for (int i=0; i transectVertices = transects[i]; if (reverseVertices) { @@ -436,15 +473,21 @@ void CorridorScanComplexItem::_rebuildTransects(void) normalizedTransectPosition += transectSpacing; } } +} +void CorridorScanComplexItem::_rebuildTransectsPhase2(void) +{ // Calculate distance flown for complex item _complexDistance = 0; for (int i=0; i<_transectPoints.count() - 2; i++) { _complexDistance += _transectPoints[i].value().distanceTo(_transectPoints[i+1].value()); } - if (_cameraTriggerInTurnAroundFact.rawValue().toDouble()) { + if (_cameraTriggerInTurnAroundFact.rawValue().toBool()) { _cameraShots = qCeil(_complexDistance / _cameraCalc.adjustedFootprintFrontal()->rawValue().toDouble()); + } else { + int singleTransectImageCount = qCeil(_corridorPolyline.length() / _cameraCalc.adjustedFootprintFrontal()->rawValue().toDouble()); + _cameraShots = singleTransectImageCount * _transectCount(); } _coordinate = _transectPoints.count() ? _transectPoints.first().value() : QGeoCoordinate(); @@ -460,5 +503,6 @@ void CorridorScanComplexItem::_rebuildTransects(void) void CorridorScanComplexItem::_rebuildCorridor(void) { _rebuildCorridorPolygon(); - _rebuildTransects(); + _rebuildTransectsPhase1(); + _rebuildTransectsPhase2(); } diff --git a/src/MissionManager/CorridorScanComplexItem.h b/src/MissionManager/CorridorScanComplexItem.h index 01c1983ff05f465ee1dbb8e084a62570cafb03b9..f929d4875a3c24de2f26426b725a3499fec76183 100644 --- a/src/MissionManager/CorridorScanComplexItem.h +++ b/src/MissionManager/CorridorScanComplexItem.h @@ -43,7 +43,7 @@ public: // Overrides from TransectStyleComplexItem - void save (QJsonArray& missionItems) final; + void save (QJsonArray& planItems) final; bool specifiesCoordinate (void) const final; void appendMissionItems (QList& items, QObject* missionItemParent) final; void applyNewAltitude (double newAltitude) final; @@ -54,17 +54,19 @@ public: static const char* corridorWidthName; private slots: - void _polylineDirtyChanged (bool dirty); - void _polylineCountChanged (int count); - void _rebuildCorridor (void); + void _polylineDirtyChanged (bool dirty); + void _polylineCountChanged (int count); + void _rebuildCorridor (void); // Overrides from TransectStyleComplexItem - virtual void _rebuildTransects (void) final; + void _rebuildTransectsPhase1 (void) final; + void _rebuildTransectsPhase2 (void) final; private: - int _transectCount (void) const; - void _rebuildCorridorPolygon(void); - + int _transectCount (void) const; + void _rebuildCorridorPolygon (void); + void _buildAndAppendMissionItems(QList& items, QObject* missionItemParent); + void _appendLoadedMissionItems (QList& items, QObject* missionItemParent); QGCMapPolyline _corridorPolyline; QList> _transectSegments; ///< Internal transect segments including grid exit, turnaround and internal camera points @@ -75,5 +77,5 @@ private: QMap _metaDataMap; SettingsFact _corridorWidthFact; - static const char* _entryPointName; + static const char* _jsonEntryPointKey; }; diff --git a/src/MissionManager/TransectStyleComplexItem.cc b/src/MissionManager/TransectStyleComplexItem.cc index 27c1f54018ff3df37873a45df5a86ffbe5fd83b7..1af62a8c604a985a681987ce70ecbb8f3e865c23 100644 --- a/src/MissionManager/TransectStyleComplexItem.cc +++ b/src/MissionManager/TransectStyleComplexItem.cc @@ -27,19 +27,23 @@ const char* TransectStyleComplexItem::cameraTriggerInTurnAroundName = "Cam const char* TransectStyleComplexItem::hoverAndCaptureName = "HoverAndCapture"; const char* TransectStyleComplexItem::refly90DegreesName = "Refly90Degrees"; -const char* TransectStyleComplexItem::_jsonCameraCalcKey = "CameraCalc"; +const char* TransectStyleComplexItem::_jsonTransectStyleComplexItemKey = "TransectStyleComplexItem"; +const char* TransectStyleComplexItem::_jsonCameraCalcKey = "CameraCalc"; +const char* TransectStyleComplexItem::_jsonTransectPointsKey = "TransectPoints"; +const char* TransectStyleComplexItem::_jsonItemsKey = "Items"; TransectStyleComplexItem::TransectStyleComplexItem(Vehicle* vehicle, QString settingsGroup, QObject* parent) - : ComplexMissionItem (vehicle, parent) - , _settingsGroup (settingsGroup) - , _sequenceNumber (0) - , _dirty (false) - , _ignoreRecalc (false) - , _complexDistance (0) - , _cameraShots (0) - , _cameraMinTriggerInterval (0) - , _cameraCalc (vehicle) - , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/TransectStyle.SettingsGroup.json"), this)) + : ComplexMissionItem (vehicle, parent) + , _settingsGroup (settingsGroup) + , _sequenceNumber (0) + , _dirty (false) + , _ignoreRecalc (false) + , _complexDistance (0) + , _cameraShots (0) + , _cameraMinTriggerInterval (0) + , _cameraCalc (vehicle) + , _loadedMissionItemsParent (NULL) + , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/TransectStyle.SettingsGroup.json"), this)) , _turnAroundDistanceFact (_settingsGroup, _metaDataMap[_vehicle->multiRotor() ? turnAroundDistanceMultiRotorName : turnAroundDistanceName]) , _cameraTriggerInTurnAroundFact(_settingsGroup, _metaDataMap[cameraTriggerInTurnAroundName]) , _hoverAndCaptureFact (_settingsGroup, _metaDataMap[hoverAndCaptureName]) @@ -108,14 +112,38 @@ void TransectStyleComplexItem::setDirty(bool dirty) void TransectStyleComplexItem::_save(QJsonObject& complexObject) { - complexObject[turnAroundDistanceName] = _turnAroundDistanceFact.rawValue().toDouble(); - complexObject[cameraTriggerInTurnAroundName] = _cameraTriggerInTurnAroundFact.rawValue().toBool(); - complexObject[hoverAndCaptureName] = _hoverAndCaptureFact.rawValue().toBool(); - complexObject[refly90DegreesName] = _refly90DegreesFact.rawValue().toBool(); + QJsonObject innerObject; + + innerObject[JsonHelper::jsonVersionKey] = 1; + innerObject[turnAroundDistanceName] = _turnAroundDistanceFact.rawValue().toDouble(); + innerObject[cameraTriggerInTurnAroundName] = _cameraTriggerInTurnAroundFact.rawValue().toBool(); + innerObject[hoverAndCaptureName] = _hoverAndCaptureFact.rawValue().toBool(); + innerObject[refly90DegreesName] = _refly90DegreesFact.rawValue().toBool(); QJsonObject cameraCalcObject; _cameraCalc.save(cameraCalcObject); - complexObject[_jsonCameraCalcKey] = cameraCalcObject; + innerObject[_jsonCameraCalcKey] = cameraCalcObject; + + QJsonValue transectPointsJson; + + // Save transects polyline + JsonHelper::saveGeoCoordinateArray(_transectPoints, false /* writeAltitude */, transectPointsJson); + innerObject[_jsonTransectPointsKey] = transectPointsJson; + + // Save the interal mission items + QJsonArray missionItemsJsonArray; + QObject* missionItemParent = new QObject(); + QList missionItems; + appendMissionItems(missionItems, missionItemParent); + foreach (const MissionItem* missionItem, missionItems) { + QJsonObject missionItemJsonObject; + missionItem->save(missionItemJsonObject); + missionItemsJsonArray.append(missionItemJsonObject); + } + missionItemParent->deleteLater(); + innerObject[_jsonItemsKey] = missionItemsJsonArray; + + complexObject[_jsonTransectStyleComplexItemKey] = innerObject; } void TransectStyleComplexItem::setSequenceNumber(int sequenceNumber) @@ -129,25 +157,65 @@ void TransectStyleComplexItem::setSequenceNumber(int sequenceNumber) bool TransectStyleComplexItem::_load(const QJsonObject& complexObject, QString& errorString) { + QList keyInfoList = { + { _jsonTransectStyleComplexItemKey, QJsonValue::Object, true }, + }; + if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) { + return false; + } + + // The TransectStyleComplexItem is a sub-object of the main complex item object + QJsonObject innerObject = complexObject[_jsonTransectStyleComplexItemKey].toObject(); + + QList innerKeyInfoList = { + { JsonHelper::jsonVersionKey, QJsonValue::Double, true }, { turnAroundDistanceName, QJsonValue::Double, true }, { cameraTriggerInTurnAroundName, QJsonValue::Bool, true }, { hoverAndCaptureName, QJsonValue::Bool, true }, { refly90DegreesName, QJsonValue::Bool, true }, { _jsonCameraCalcKey, QJsonValue::Object, true }, + { _jsonTransectPointsKey, QJsonValue::Array, true }, + { _jsonItemsKey, QJsonValue::Array, true }, }; - if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) { + if (!JsonHelper::validateKeys(innerObject, innerKeyInfoList, errorString)) { return false; } - if (!_cameraCalc.load(complexObject[_jsonCameraCalcKey].toObject(), errorString)) { + int version = innerObject[JsonHelper::jsonVersionKey].toInt(); + if (version != 1) { + errorString = tr("TransectStyleComplexItem version %2 not supported").arg(version); return false; } - _turnAroundDistanceFact.setRawValue (complexObject[turnAroundDistanceName].toDouble()); - _cameraTriggerInTurnAroundFact.setRawValue (complexObject[cameraTriggerInTurnAroundName].toBool()); - _hoverAndCaptureFact.setRawValue (complexObject[hoverAndCaptureName].toBool()); - _hoverAndCaptureFact.setRawValue (complexObject[refly90DegreesName].toBool()); + // Load transect points + if (!JsonHelper::loadGeoCoordinateArray(innerObject[_jsonTransectPointsKey], false /* altitudeRequired */, _transectPoints, errorString)) { + return false; + } + + // Load generated mission items + _loadedMissionItemsParent = new QObject(this); + QJsonArray missionItemsJsonArray = innerObject[_jsonItemsKey].toArray(); + foreach (const QJsonValue& missionItemJson, missionItemsJsonArray) { + MissionItem* missionItem = new MissionItem(_loadedMissionItemsParent); + if (!missionItem->load(missionItemJson.toObject(), 0 /* sequenceNumber */, errorString)) { + _loadedMissionItemsParent->deleteLater(); + _loadedMissionItemsParent = NULL; + return false; + } + _loadedMissionItems.append(missionItem); + } + + // Load CameraCalc data + if (!_cameraCalc.load(innerObject[_jsonCameraCalcKey].toObject(), errorString)) { + return false; + } + + // Load TransectStyleComplexItem individual values + _turnAroundDistanceFact.setRawValue (innerObject[turnAroundDistanceName].toDouble()); + _cameraTriggerInTurnAroundFact.setRawValue (innerObject[cameraTriggerInTurnAroundName].toBool()); + _hoverAndCaptureFact.setRawValue (innerObject[hoverAndCaptureName].toBool()); + _hoverAndCaptureFact.setRawValue (innerObject[refly90DegreesName].toBool()); return true; } @@ -230,3 +298,8 @@ bool TransectStyleComplexItem::hoverAndCaptureAllowed(void) const return _vehicle->multiRotor() || _vehicle->vtol(); } +void TransectStyleComplexItem::_rebuildTransects(void) +{ + _rebuildTransectsPhase1(); + _rebuildTransectsPhase2(); +} diff --git a/src/MissionManager/TransectStyleComplexItem.h b/src/MissionManager/TransectStyleComplexItem.h index d624557eb4509d5736600147aa364a7b1253bb29..2afc9fbaf8c2a8414e115aaa8e60f445f1b8d8ca 100644 --- a/src/MissionManager/TransectStyleComplexItem.h +++ b/src/MissionManager/TransectStyleComplexItem.h @@ -66,7 +66,7 @@ public: // Overrides from VisualMissionItem - void save (QJsonArray& missionItems) override = 0; + void save (QJsonArray& planItems) override = 0; bool specifiesCoordinate (void) const override = 0; void appendMissionItems (QList& items, QObject* missionItemParent) override = 0; void applyNewAltitude (double newAltitude) override = 0; @@ -108,7 +108,8 @@ signals: void coveredAreaChanged (void); protected slots: - virtual void _rebuildTransects (void) = 0; + virtual void _rebuildTransectsPhase1 (void) = 0; + virtual void _rebuildTransectsPhase2 (void) = 0; void _setDirty (void); void _setIfDirty (bool dirty); @@ -121,7 +122,6 @@ protected: void _setExitCoordinate (const QGeoCoordinate& coordinate); void _setCameraShots (int cameraShots); double _triggerDistance (void) const; - int _transectCount (void) const; bool _hasTurnaround (void) const; double _turnaroundDistance (void) const; @@ -141,6 +141,9 @@ protected: double _cruiseSpeed; CameraCalc _cameraCalc; + QObject* _loadedMissionItemsParent; ///< Parent for all items in _loadedMissionItems for simpler delete + QList _loadedMissionItems; ///< Mission items loaded from plan file + QMap _metaDataMap; SettingsFact _turnAroundDistanceFact; @@ -149,4 +152,10 @@ protected: SettingsFact _refly90DegreesFact; static const char* _jsonCameraCalcKey; + static const char* _jsonTransectStyleComplexItemKey; + static const char* _jsonTransectPointsKey; + static const char* _jsonItemsKey; + +private slots: + void _rebuildTransects(void); }; diff --git a/src/MissionManager/TransectStyleComplexItemTest.cc b/src/MissionManager/TransectStyleComplexItemTest.cc index a9f2372af32e32225d8bfdbf1612ce063f09f790..2ca3b0eef3147122c25ea1a3c948192cd77e8b1a 100644 --- a/src/MissionManager/TransectStyleComplexItemTest.cc +++ b/src/MissionManager/TransectStyleComplexItemTest.cc @@ -174,7 +174,12 @@ TransectStyleItem::TransectStyleItem(Vehicle* vehicle, QObject* parent) } -void TransectStyleItem::_rebuildTransects(void) +void TransectStyleItem::_rebuildTransectsPhase1(void) { rebuildTransectsCalled = true; } + +void TransectStyleItem::_rebuildTransectsPhase2(void) +{ + +} diff --git a/src/MissionManager/TransectStyleComplexItemTest.h b/src/MissionManager/TransectStyleComplexItemTest.h index d3aeea3202af69898f5d74f5098f99b84182756f..b6648fdb083c034a6a0810e25522cafe35e6065f 100644 --- a/src/MissionManager/TransectStyleComplexItemTest.h +++ b/src/MissionManager/TransectStyleComplexItemTest.h @@ -101,5 +101,6 @@ public: private slots: // Overrides from TransectStyleComplexItem - void _rebuildTransects (void) final; + void _rebuildTransectsPhase1(void) final; + void _rebuildTransectsPhase2(void) final; };