Commit 4b4a03da authored by Don Gagne's avatar Don Gagne Committed by GitHub
Browse files

Merge pull request #4383 from DonLakeFlyer/MissionFileFormatV2

New V2 mission file format
parents 0800b78e 388a9551
......@@ -97,10 +97,12 @@ void JsonHelper::saveGeoCoordinate(const QGeoCoordinate& coordinate,
bool JsonHelper::validateKeyTypes(const QJsonObject& jsonObject, const QStringList& keys, const QList<QJsonValue::Type>& types, QString& errorString)
{
for (int i=0; i<keys.count(); i++) {
if (jsonObject.contains(keys[i])) {
if (jsonObject.value(keys[i]).type() != types[i]) {
errorString = QObject::tr("Incorrect type key:type:expected %1 %2 %3").arg(keys[i]).arg(jsonObject.value(keys[i]).type()).arg(types[i]);
for (int i=0; i<types.count(); i++) {
QString valueKey = keys[i];
if (jsonObject.contains(valueKey)) {
const QJsonValue& jsonValue = jsonObject[valueKey];
if (jsonValue.type() != types[i]) {
errorString = QObject::tr("Incorrect value type - key:type:expected %1:%2:%3").arg(valueKey).arg(_jsonValueTypeToString(jsonValue.type())).arg(_jsonValueTypeToString(types[i]));
return false;
}
}
......@@ -141,14 +143,13 @@ bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc)
bool JsonHelper::validateQGCJsonFile(const QJsonObject& jsonObject,
const QString& expectedFileType,
int supportedMajorVersion,
int supportedMinorVersion,
int& fileMajorVersion,
int& fileMinorVersion,
int minSupportedVersion,
int maxSupportedVersion,
int& version,
QString& errorString)
{
// Check for required keys
QStringList requiredKeys = { jsonVersionKey, jsonFileTypeKey };
QStringList requiredKeys = { jsonFileTypeKey, jsonGroundStationKey, jsonVersionKey };
if (!validateRequiredKeys(jsonObject, requiredKeys, errorString)) {
return false;
}
......@@ -166,25 +167,24 @@ bool JsonHelper::validateQGCJsonFile(const QJsonObject& jsonObject,
return false;
}
// Parse and validate version
// Check version - support both old style v1 string and new style integer
QString incorrectVersionFormatErrorString = QObject::tr("Incorrectly formatted version value");
QRegularExpression versionRegExp("(\\d+).(\\d+)");
QRegularExpressionMatch match = versionRegExp.match(jsonObject[jsonVersionKey].toString());
if (!match.hasMatch()) {
errorString = incorrectVersionFormatErrorString;
return false;
QJsonValue versionValue = jsonObject[jsonVersionKey];
if (versionValue.type() == QJsonValue::String && versionValue.toString() == QStringLiteral("1.0")) {
version = 1;
} else {
if (versionValue.type() != QJsonValue::Double) {
errorString = QObject::tr("Incorrect type for version value, must be integer");
return false;
}
version = versionValue.toInt();
}
QStringList versionParts = match.capturedTexts();
if (versionParts.count() != 3) {
errorString = incorrectVersionFormatErrorString;
if (version < minSupportedVersion) {
errorString = QObject::tr("File version %1 is no longer supported").arg(version);
return false;
}
fileMajorVersion = versionParts[0].toInt();
fileMinorVersion = versionParts[0].toInt();
if (fileMajorVersion > supportedMajorVersion || (fileMajorVersion == supportedMajorVersion && fileMinorVersion > supportedMinorVersion)) {
errorString = QObject::tr("File version (%1.%2) is larger than current supported version (%3.%4)").arg(fileMajorVersion).arg(fileMinorVersion).arg(supportedMajorVersion).arg(supportedMinorVersion);
if (version > maxSupportedVersion) {
errorString = QObject::tr("File version %1 is newer than current supported version %2").arg(version).arg(maxSupportedVersion);
return false;
}
......@@ -284,3 +284,27 @@ bool JsonHelper::validateKeys(const QJsonObject& jsonObject, const QList<JsonHel
}
return validateKeyTypes(jsonObject, keyList, typeList, errorString);
}
QString JsonHelper::_jsonValueTypeToString(QJsonValue::Type type)
{
const struct {
QJsonValue::Type type;
const char* string;
} rgTypeToString[] = {
{ QJsonValue::Null, "NULL" },
{ QJsonValue::Bool, "Bool" },
{ QJsonValue::Double, "Double" },
{ QJsonValue::String, "String" },
{ QJsonValue::Array, "Array" },
{ QJsonValue::Object, "Object" },
{ QJsonValue::Undefined, "Undefined" },
};
for (size_t i=0; i<sizeof(rgTypeToString)/sizeof(rgTypeToString[0]); i++) {
if (type == rgTypeToString[i].type) {
return rgTypeToString[i].string;
}
}
return QObject::tr("Unknown type: %1").arg(type);
}
......@@ -25,13 +25,13 @@ public:
/// Validates the standard parts of a QGC json file:
/// jsonFileTypeKey - Required and checked to be equal to expectedFileType
/// jsonVersionKey - Required and checked to be below supportedMajorVersion, supportedMinorVersion
/// jsonGroundStationKey - Required and checked to be string type
/// @return false: validation failed
static bool validateQGCJsonFile(const QJsonObject& jsonObject, ///< top level json object in file
static bool validateQGCJsonFile(const QJsonObject& jsonObject, ///< root json object
const QString& expectedFileType, ///< correct file type for file
int supportedMajorVersion, ///< maximum supported major version
int supportedMinorVersion, ///< maximum supported minor version
int &fileMajorVersion, ///< returned file major version
int &fileMinorVersion, ///< returned file minor version
int minSupportedVersion, ///< minimum supported version
int maxSupportedVersion, ///< maximum supported major version
int &version, ///< returned file version
QString& errorString); ///< returned error string if validation fails
static bool validateRequiredKeys(const QJsonObject& jsonObject, const QStringList& keys, QString& errorString);
......@@ -85,6 +85,8 @@ public:
static const char* jsonFileTypeKey;
private:
static QString _jsonValueTypeToString(QJsonValue::Type type);
static const char* _enumStringsJsonKey;
static const char* _enumValuesJsonKey;
};
......
......@@ -7,9 +7,10 @@
*
****************************************************************************/
#include "ComplexMissionItem.h"
const char* ComplexMissionItem::jsonComplexItemTypeKey = "complexItemType";
ComplexMissionItem::ComplexMissionItem(Vehicle* vehicle, QObject* parent)
: VisualMissionItem(vehicle, parent)
{
......
......@@ -36,15 +36,19 @@ public:
/// Load the complex mission item from Json
/// @param complexObject Complex mission item json object
/// @param sequenceNumber Sequence number for first MISSION_ITEM in survey
/// @param[out] errorString Error if load fails
/// @return true: load success, false: load failed, errorString set
virtual bool load(const QJsonObject& complexObject, QString& errorString) = 0;
virtual bool load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString) = 0;
/// Get the point of complex mission item furthest away from a coordinate
/// @param other QGeoCoordinate to which distance is calculated
/// @return the greatest distance from any point of the complex item to some coordinate
virtual double greatestDistanceTo(const QGeoCoordinate &other) const = 0;
/// This mission item attribute specifies the type of the complex item.
static const char* jsonComplexItemTypeKey;
signals:
void lastSequenceNumberChanged (int lastSequenceNumber);
void complexDistanceChanged (double complexDistance);
......
......@@ -103,27 +103,13 @@ bool GeoFenceController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorStr
{
QJsonObject json = jsonDoc.object();
// Check for required keys
QStringList requiredKeys;
requiredKeys << JsonHelper::jsonVersionKey << JsonHelper::jsonFileTypeKey;
if (!JsonHelper::validateRequiredKeys(json, requiredKeys, errorString)) {
return false;
}
#if 0
// Validate base key types
QStringList keyList;
QList<QJsonValue::Type> typeList;
keyList << jsonSimpleItemsKey << _jsonVersionKey << _jsonGroundStationKey << _jsonMavAutopilotKey << _jsonComplexItemsKey << _jsonPlannedHomePositionKey;
typeList << QJsonValue::Array << QJsonValue::String << QJsonValue::String << QJsonValue::Double << QJsonValue::Array << QJsonValue::Object;
if (!JsonHelper::validateKeyTypes(json, keyList, typeList, errorString)) {
return false;
}
#endif
// Version check
if (json[JsonHelper::jsonVersionKey].toString() != "1.0") {
errorString = QStringLiteral("QGroundControl does not support this file version");
int fileVersion;
if (!JsonHelper::validateQGCJsonFile(json,
_jsonFileTypeValue, // expected file type
1, // minimum supported version
1, // maximum supported version
fileVersion,
errorString)) {
return false;
}
......@@ -269,7 +255,7 @@ void GeoFenceController::saveToFile(const QString& filename)
QJsonObject fenceFileObject; // top level json object
fenceFileObject[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue;
fenceFileObject[JsonHelper::jsonVersionKey] = QStringLiteral("1.0");
fenceFileObject[JsonHelper::jsonVersionKey] = 1;
fenceFileObject[JsonHelper::jsonGroundStationKey] = JsonHelper::jsonGroundStationValue;
QStringList paramNames;
......
......@@ -27,12 +27,19 @@
QGC_LOGGING_CATEGORY(MissionControllerLog, "MissionControllerLog")
const char* MissionController::jsonSimpleItemsKey = "items";
const char* MissionController::_settingsGroup = "MissionController";
const char* MissionController::_jsonMavAutopilotKey = "MAV_AUTOPILOT";
const char* MissionController::_jsonComplexItemsKey = "complexItems";
const char* MissionController::_jsonFileTypeValue = "Mission";
const char* MissionController::_jsonItemsKey = "items";
const char* MissionController::_jsonPlannedHomePositionKey = "plannedHomePosition";
const char* MissionController::_jsonFirmwareTypeKey = "firmwareType";
const char* MissionController::_jsonParamsKey = "params";
// Deprecated V1 format keys
const char* MissionController::_jsonComplexItemsKey = "complexItems";
const char* MissionController::_jsonMavAutopilotKey = "MAV_AUTOPILOT";
const int MissionController::_missionFileVersion = 2;
MissionController::MissionController(QObject *parent)
: PlanElementController(parent)
......@@ -252,28 +259,40 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectL
errorString = jsonParseError.errorString();
return false;
}
QJsonObject json = jsonDoc.object();
// Check for required keys
QStringList requiredKeys;
requiredKeys << JsonHelper::jsonVersionKey << _jsonPlannedHomePositionKey;
if (!JsonHelper::validateRequiredKeys(json, requiredKeys, errorString)) {
return false;
// V1 file format has no file type key and version key is string. Convert to new format.
if (!json.contains(JsonHelper::jsonFileTypeKey)) {
json[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue;
}
// Validate base key types
QStringList keyList;
QList<QJsonValue::Type> typeList;
keyList << jsonSimpleItemsKey << JsonHelper::jsonVersionKey << JsonHelper::jsonGroundStationKey << _jsonMavAutopilotKey << _jsonComplexItemsKey << _jsonPlannedHomePositionKey;
typeList << QJsonValue::Array << QJsonValue::String << QJsonValue::String << QJsonValue::Double << QJsonValue::Array << QJsonValue::Object;
if (!JsonHelper::validateKeyTypes(json, keyList, typeList, errorString)) {
int fileVersion;
if (!JsonHelper::validateQGCJsonFile(json,
_jsonFileTypeValue, // expected file type
1, // minimum supported version
2, // maximum supported version
fileVersion,
errorString)) {
return false;
}
// Version check
if (json[JsonHelper::jsonVersionKey].toString() != "1.0") {
errorString = QStringLiteral("QGroundControl does not support this file version");
if (fileVersion == 1) {
return _loadJsonMissionFileV1(json, visualItems, complexItems, errorString);
} else {
return _loadJsonMissionFileV2(json, visualItems, complexItems, errorString);
}
}
bool MissionController::_loadJsonMissionFileV1(const QJsonObject& json, QmlObjectListModel* visualItems, QmlObjectListModel* complexItems, QString& errorString)
{
// Validate root object keys
QList<JsonHelper::KeyValidateInfo> rootKeyInfoList = {
{ _jsonPlannedHomePositionKey, QJsonValue::Object, true },
{ _jsonItemsKey, QJsonValue::Array, true },
{ _jsonMavAutopilotKey, QJsonValue::Double, true },
{ _jsonComplexItemsKey, QJsonValue::Array, true },
};
if (!JsonHelper::validateKeys(json, rootKeyInfoList, errorString)) {
return false;
}
......@@ -289,8 +308,8 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectL
}
SurveyMissionItem* item = new SurveyMissionItem(_activeVehicle, this);
if (item->load(itemValue.toObject(), errorString)) {
qCDebug(MissionControllerLog) << "Json load: complex item start:stop" << item->sequenceNumber() << item->lastSequenceNumber();
const QJsonObject itemObject = itemValue.toObject();
if (item->load(itemObject, itemObject["id"].toInt(), errorString)) {
complexItems->append(item);
} else {
return false;
......@@ -302,7 +321,7 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectL
int nextSimpleItemIndex= 0;
int nextComplexItemIndex= 0;
int nextSequenceNumber = 1; // Start with 1 since home is in 0
QJsonArray itemArray(json[jsonSimpleItemsKey].toArray());
QJsonArray itemArray(json[_jsonItemsKey].toArray());
qCDebug(MissionControllerLog) << "Json load: simple item loop start simpleItemCount:ComplexItemCount" << itemArray.count() << complexItems->count();
do {
......@@ -330,8 +349,9 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectL
return false;
}
const QJsonObject itemObject = itemValue.toObject();
SimpleMissionItem* item = new SimpleMissionItem(_activeVehicle, this);
if (item->load(itemValue.toObject(), errorString)) {
if (item->load(itemObject, itemObject["id"].toInt(), errorString)) {
qCDebug(MissionControllerLog) << "Json load: adding simple item expectedSequence:actualSequence" << nextSequenceNumber << item->sequenceNumber();
visualItems->append(item);
} else {
......@@ -345,7 +365,7 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectL
if (json.contains(_jsonPlannedHomePositionKey)) {
SimpleMissionItem* item = new SimpleMissionItem(_activeVehicle, this);
if (item->load(json[_jsonPlannedHomePositionKey].toObject(), errorString)) {
if (item->load(json[_jsonPlannedHomePositionKey].toObject(), 0, errorString)) {
visualItems->insert(0, item);
} else {
return false;
......@@ -357,6 +377,117 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectL
return true;
}
bool MissionController::_loadJsonMissionFileV2(const QJsonObject& json, QmlObjectListModel* visualItems, QmlObjectListModel* complexItems, QString& errorString)
{
// Validate root object keys
QList<JsonHelper::KeyValidateInfo> rootKeyInfoList = {
{ _jsonPlannedHomePositionKey, QJsonValue::Array, true },
{ _jsonItemsKey, QJsonValue::Array, true },
{ _jsonFirmwareTypeKey, QJsonValue::Double, true },
};
if (!JsonHelper::validateKeys(json, rootKeyInfoList, errorString)) {
return false;
}
qCDebug(MissionControllerLog) << "MissionController::_loadJsonMissionFileV2 itemCount:" << json[_jsonItemsKey].toArray().count();
// Planned home position
QGeoCoordinate homeCoordinate;
if (!JsonHelper::loadGeoCoordinate(json[_jsonPlannedHomePositionKey], true /* altitudeRequired */, homeCoordinate, errorString)) {
return false;
}
SimpleMissionItem* homeItem = new SimpleMissionItem(_activeVehicle, this);
homeItem->setCoordinate(homeCoordinate);
visualItems->insert(0, homeItem);
qCDebug(MissionControllerLog) << "plannedHomePosition" << homeCoordinate;
// Read mission items
int nextSequenceNumber = 1; // Start with 1 since home is in 0
const QJsonArray rgMissionItems(json[_jsonItemsKey].toArray());
for (int i=0; i<rgMissionItems.count(); i++) {
// Convert to QJsonObject
const QJsonValue& itemValue = rgMissionItems[i];
if (!itemValue.isObject()) {
errorString = tr("Mission item %1 is not an object").arg(i);
return false;
}
const QJsonObject itemObject = itemValue.toObject();
// Load item based on type
QList<JsonHelper::KeyValidateInfo> itemKeyInfoList = {
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
};
if (!JsonHelper::validateKeys(itemObject, itemKeyInfoList, errorString)) {
return false;
}
QString itemType = itemObject[VisualMissionItem::jsonTypeKey].toString();
if (itemType == VisualMissionItem::jsonTypeSimpleItemValue) {
qCDebug(MissionControllerLog) << "Loading MISSION_ITEM: nextSequenceNumber" << nextSequenceNumber;
SimpleMissionItem* simpleItem = new SimpleMissionItem(_activeVehicle, this);
if (simpleItem->load(itemObject, nextSequenceNumber++, errorString)) {
visualItems->append(simpleItem);
} else {
return false;
}
} else if (itemType == VisualMissionItem::jsonTypeComplexItemValue) {
QList<JsonHelper::KeyValidateInfo> complexItemKeyInfoList = {
{ ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true },
};
if (!JsonHelper::validateKeys(itemObject, complexItemKeyInfoList, errorString)) {
return false;
}
QString complexItemType = itemObject[ComplexMissionItem::jsonComplexItemTypeKey].toString();
if (complexItemType == SurveyMissionItem::jsonComplexItemTypeValue) {
qCDebug(MissionControllerLog) << "Loading Survey: nextSequenceNumber" << nextSequenceNumber;
SurveyMissionItem* surveyItem = new SurveyMissionItem(_activeVehicle, this);
if (!surveyItem->load(itemObject, nextSequenceNumber++, errorString)) {
return false;
}
nextSequenceNumber = surveyItem->lastSequenceNumber() + 1;
qCDebug(MissionControllerLog) << "Survey load complete: nextSequenceNumber" << nextSequenceNumber;
visualItems->append(surveyItem);
complexItems->append(surveyItem);
} else {
errorString = tr("Unsupported complex item type: %1").arg(complexItemType);
}
} else {
errorString = tr("Unknown item type: %1").arg(itemType);
return false;
}
}
// Fix up the DO_JUMP commands jump sequence number by finding the item with the matching doJumpId
for (int i=0; i<visualItems->count(); i++) {
if (visualItems->value<VisualMissionItem*>(i)->isSimpleItem()) {
SimpleMissionItem* doJumpItem = visualItems->value<SimpleMissionItem*>(i);
if ((MAV_CMD)doJumpItem->command() == MAV_CMD_DO_JUMP) {
bool found = false;
int findDoJumpId = doJumpItem->missionItem().param1();
for (int j=0; j<visualItems->count(); j++) {
if (visualItems->value<VisualMissionItem*>(j)->isSimpleItem()) {
SimpleMissionItem* targetItem = visualItems->value<SimpleMissionItem*>(j);
if (targetItem->missionItem().doJumpId() == findDoJumpId) {
doJumpItem->missionItem().setParam1(targetItem->sequenceNumber());
found = true;
break;
}
}
}
if (!found) {
errorString = tr("Could not find doJumpId: %1").arg(findDoJumpId);
return false;
}
}
}
}
return true;
}
bool MissionController::_loadTextMissionFile(QTextStream& stream, QmlObjectListModel* visualItems, QString& errorString)
{
bool addPlannedHomePosition = false;
......@@ -498,10 +629,8 @@ void MissionController::saveToFile(const QString& filename)
qgcApp()->showMessage(file.errorString());
} else {
QJsonObject missionFileObject; // top level json object
QJsonArray simpleItemsObject;
QJsonArray complexItemsObject;
missionFileObject[JsonHelper::jsonVersionKey] = "1.0";
missionFileObject[JsonHelper::jsonVersionKey] = _missionFileVersion;
missionFileObject[JsonHelper::jsonGroundStationKey] = JsonHelper::jsonGroundStationValue;
MAV_AUTOPILOT firmwareType = MAV_AUTOPILOT_GENERIC;
......@@ -514,35 +643,28 @@ void MissionController::saveToFile(const QString& filename)
QSettings settings;
firmwareType = (MAV_AUTOPILOT)settings.value("OfflineEditingFirmwareType", MAV_AUTOPILOT_ARDUPILOTMEGA).toInt();
}
missionFileObject[_jsonMavAutopilotKey] = firmwareType;
missionFileObject[_jsonFirmwareTypeKey] = firmwareType;
// Save planned home position
QJsonObject homePositionObject;
SimpleMissionItem* homeItem = qobject_cast<SimpleMissionItem*>(_visualItems->get(0));
if (homeItem) {
homeItem->missionItem().save(homePositionObject);
} else {
if (!homeItem) {
qgcApp()->showMessage(QStringLiteral("Internal error: VisualMissionItem at index 0 not SimpleMissionItem"));
return;
}
missionFileObject[_jsonPlannedHomePositionKey] = homePositionObject;
QJsonValue coordinateValue;
JsonHelper::saveGeoCoordinate(homeItem->coordinate(), true /* writeAltitude */, coordinateValue);
missionFileObject[_jsonPlannedHomePositionKey] = coordinateValue;
// Save the visual items
QJsonArray rgMissionItems;
for (int i=1; i<_visualItems->count(); i++) {
QJsonObject itemObject;
VisualMissionItem* visualItem = qobject_cast<VisualMissionItem*>(_visualItems->get(i));
visualItem->save(itemObject);
if (visualItem->isSimpleItem()) {
simpleItemsObject.append(itemObject);
} else {
complexItemsObject.append(itemObject);
}
rgMissionItems.append(itemObject);
}
missionFileObject[jsonSimpleItemsKey] = simpleItemsObject;
missionFileObject[_jsonComplexItemsKey] = complexItemsObject;
missionFileObject[_jsonItemsKey] = rgMissionItems;
QJsonDocument saveDoc(missionFileObject);
file.write(saveDoc.toJson());
......@@ -657,7 +779,7 @@ void MissionController::_recalcWaypointLines(void)
// Create a new segment and wire update notifiers
auto linevect = new CoordinateVector(lastCoordinateItem->isSimpleItem() ? lastCoordinateItem->coordinate() : lastCoordinateItem->exitCoordinate(), item->coordinate(), this);
auto originNotifier = lastCoordinateItem->isSimpleItem() ? &VisualMissionItem::coordinateChanged : &VisualMissionItem::exitCoordinateChanged,
endNotifier = &VisualMissionItem::coordinateChanged;
endNotifier = &VisualMissionItem::coordinateChanged;
// Use signals/slots to update the coordinate endpoints
connect(lastCoordinateItem, originNotifier, linevect, &CoordinateVector::setCoordinate1);
connect(item, endNotifier, linevect, &CoordinateVector::setCoordinate2);
......@@ -883,7 +1005,7 @@ void MissionController::_recalcSequence(void)
ComplexMissionItem* complexItem = qobject_cast<ComplexMissionItem*>(item);
if (complexItem) {
sequenceNumber = complexItem->lastSequenceNumber() + 1;
sequenceNumber = complexItem->lastSequenceNumber() + 1;
} else {
qWarning() << "isSimpleItem == false, yet not ComplexMissionItem";
}
......
......@@ -88,7 +88,6 @@ public:
void setCruiseDistance (double cruiseDistance );
void setHoverDistance (double hoverDistance );
static const char* jsonSimpleItemsKey; ///< Key for simple items in a json file
signals:
void plannedHomePositionChanged(QGeoCoordinate plannedHomePosition);
......@@ -129,6 +128,8 @@ private:
double _normalizeLat(double lat);
double _normalizeLon(double lon);
bool _loadJsonMissionFile(const QByteArray& bytes, QmlObjectListModel* visualItems, QmlObjectListModel* complexItems, QString& errorString);
bool _loadJsonMissionFileV1(const QJsonObject& json, QmlObjectListModel* visualItems, QmlObjectListModel* complexItems, QString& errorString);
bool _loadJsonMissionFileV2(const QJsonObject& json, QmlObjectListModel* visualItems, QmlObjectListModel* complexItems, QString& errorString);
bool _loadTextMissionFile(QTextStream& stream, QmlObjectListModel* visualItems, QString& errorString);
int _nextSequenceNumber(void);
......@@ -150,9 +151,17 @@ private:
double _hoverDistance;
static const char* _settingsGroup;
static const char* _jsonFileTypeValue;
static const char* _jsonFirmwareTypeKey;
static const char* _jsonItemsKey;
static const char* _jsonPlannedHomePositionKey;
static const char* _jsonParamsKey;
// Deprecated V1 format keys
static const char* _jsonMavAutopilotKey;
static const char* _jsonComplexItemsKey;
static const char* _jsonPlannedHomePositionKey;
static const int _missionFileVersion;
};
#endif
......@@ -15,22 +15,25 @@
#include "FirmwarePluginManager.h"
#include "QGCApplication.h"
#include "JsonHelper.h"
#include "VisualMissionItem.h"
const char* MissionItem::_itemType = "missionItem";
const char* MissionItem::_jsonTypeKey = "type";
const char* MissionItem::_jsonIdKey = "id";
const char* MissionItem::_jsonFrameKey = "frame";
const char* MissionItem::_jsonCommandKey = "command";
const char* MissionItem::_jsonAutoContinueKey = "autoContinue";
const char* MissionItem::_jsonCoordinateKey = "coordinate";
const char* MissionItem::_jsonParamsKey = "params";
const char* MissionItem::_jsonDoJumpIdKey = "doJumpId";
// Deprecated V1 format keys
const char* MissionItem::_jsonParam1Key = "param1";
const char* MissionItem::_jsonParam2Key = "param2";
const char* MissionItem::_jsonParam3Key = "param3";
const char* MissionItem::_jsonParam4Key = "param4";
const char* MissionItem::_jsonAutoContinueKey = "autoContinue";
const char* MissionItem::_jsonCoordinateKey = "coordinate";
MissionItem::MissionItem(QObject* parent)
: QObject(parent)
, _sequenceNumber(0)
, _doJumpId(-1)
, _isCurrentItem(false)
, _autoContinueFact (0, "AutoContinue", FactMetaData::valueTypeUint32)
, _commandFact (0, "", FactMetaData::valueTypeUint32)
......@@ -65,6 +68,7 @@ MissionItem::MissionItem(int sequenceNumber,
QObject* parent)
: QObject(parent)
, _sequenceNumber(sequenceNumber)
, _doJumpId(-1)
, _isCurrentItem(isCurrentItem)
, _commandFact (0, "", FactMetaData::valueTypeUint32)
, _frameFact (0, "", FactMetaData::valueTypeUint32)
......@@ -96,6 +100,7 @@ MissionItem::MissionItem(int sequenceNumber,
MissionItem::MissionItem(const MissionItem& other, QObject* parent)
: QObject(parent)
, _sequenceNumber(0)
, _doJumpId(-1)
, _isCurrentItem(false)
, _commandFact (0, "", FactMetaData::valueTypeUint32)
, _frameFact (0, "", FactMetaData::valueTypeUint32)
......@@ -116,6 +121,8 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent)
const MissionItem& MissionItem::operator=(const MissionItem& other)
{
_doJumpId = other._doJumpId;
setCommand(other.command());
setFrame(other.frame());
setSequenceNumber(other._sequenceNumber);
......@@ -138,19 +145,18 @@ MissionItem::~MissionItem()
void MissionItem::save(QJsonObject& json) const
{
json[_jsonTypeKey] = _itemType;
json[_jsonIdKey] = sequenceNumber();
json[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeSimpleItemValue;
json[_jsonFrameKey] = frame();
json[_jsonCommandKey] = command();
json[_jsonParam1Key] = param1();
json[_jsonParam2Key] = param2();
json[_jsonParam3Key] = param3();
json[_jsonParam4Key] = param4();
json[_jsonAutoContinueKey] = autoContinue();
json[_jsonDoJumpIdKey] = _sequenceNumber;
QJsonArray rgParams = { param1(), param2(), param3(), param4() };
json[_jsonParamsKey] = rgParams;
QJsonArray coordinateArray;
coordinateArray << param5() << param6() << param7();
json[_jsonCoordinateKey] = coordinateArray;
QJsonValue coordinateValue;
JsonHelper::saveGeoCoordinate(QGeoCoordinate(param5(), param6(), param7()), true /* writeAltitude */, coordinateValue);
json[_jsonCoordinateKey] = coordinateValue;
}
bool MissionItem::load(QTextStream &loadStream)
......@@ -175,41 +181,98 @@ bool MissionItem::load(QTextStream &loadStream)
return false;
}
bool MissionItem::load(const QJsonObject& json, QString& errorString)
bool MissionItem::_convertJsonV1ToV2(const QJsonObject& json, QJsonObject& v2Json, QString& errorString)
{
// V1 format type = "missionItem", V2 format type = "MissionItem"
// V1 format has params in separate param[1-n] keys
// V2 format has params in params array
v2Json = json;
if (json.contains(_jsonParamsKey)) {
// Already V2 format
return true;
}
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
{ _jsonParam1Key, QJsonValue::Double, true },
{ _jsonParam2Key, QJsonValue::Double, true },
{ _jsonParam3Key, QJsonValue::Double, true },
{ _jsonParam4Key, QJsonValue::Double, true },
};
if (!JsonHelper::validateKeys(json, keyInfoList, errorString)) {
return false;
}
if (v2Json[VisualMissionItem::jsonTypeKey].toString() == QStringLiteral("missionItem")) {
v2Json[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeSimpleItemValue;
}
QJsonArray rgParams = { json[_jsonParam1Key].toDouble(), json[_jsonParam2Key].toDouble(), json[_jsonParam3Key].toDouble(), json[_jsonParam4Key].toDouble() };
v2Json[_jsonParamsKey] = rgParams;
v2Json.remove(_jsonParam1Key);
v2Json.remove(_jsonParam2Key);
v2Json.remove(_jsonParam3Key);
v2Json.remove(_jsonParam4Key);
return true;
}
bool MissionItem::load(const QJsonObject& json, int sequenceNumber, QString& errorString)
{
QStringList requiredKeys;
QJsonObject v2Json;
if (!_convertJsonV1ToV2(json, v2Json, errorString)) {
return false;
}
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
{ _jsonFrameKey, QJsonValue::Double, true },
{ _jsonCommandKey, QJsonValue::Double, true },
{ _jsonParamsKey, QJsonValue::Array, true },
{ _jsonAutoContinueKey, QJsonValue::Bool, true },
{ _jsonCoordinateKey, QJsonValue::Array, true },
{ _jsonDoJumpIdKey, QJsonValue::Double, false },
};
if (!JsonHelper::validateKeys(v2Json, keyInfoList, errorString)) {
return false;
}
requiredKeys << _jsonTypeKey << _jsonIdKey << _jsonFrameKey << _jsonCommandKey <<
_jsonParam1Key << _jsonParam2Key << _jsonParam3Key << _jsonParam4Key <<
_jsonAutoContinueKey << _jsonCoordinateKey;
if (!JsonHelper::validateRequiredKeys(json, requiredKeys, errorString)) {
if (v2Json[VisualMissionItem::jsonTypeKey] != VisualMissionItem::jsonTypeSimpleItemValue) {
errorString = tr("Type found: %1 must be: %2").arg(v2Json[VisualMissionItem::jsonTypeKey].toString()).arg(VisualMissionItem::jsonTypeSimpleItemValue);
return false;
}
if (json[_jsonTypeKey] != _itemType) {
errorString = QString("type found: %1 must be: %2").arg(json[_jsonTypeKey].toString()).arg(_itemType);
QJsonArray rgParams = v2Json[_jsonParamsKey].toArray();
if (rgParams.count() != 4) {
errorString = tr("%1 key must contains 4 values").arg(_jsonParamsKey);
return false;
}
// Make sure to set these first since they can signal other changes
setFrame((MAV_FRAME)json[_jsonFrameKey].toInt());
setCommand((MAV_CMD)json[_jsonCommandKey].toInt());
setFrame((MAV_FRAME)v2Json[_jsonFrameKey].toInt());
setCommand((MAV_CMD)v2Json[_jsonCommandKey].toInt());
QGeoCoordinate coordinate;
if (!JsonHelper::loadGeoCoordinate(json[_jsonCoordinateKey], true /* altitudeRequired */, coordinate, errorString)) {
if (!JsonHelper::loadGeoCoordinate(v2Json[_jsonCoordinateKey], true /* altitudeRequired */, coordinate, errorString)) {
return false;
}
setParam5(coordinate.latitude());
setParam6(coordinate.longitude());
setParam7(coordinate.altitude());
_doJumpId = -1;
if (v2Json.contains(_jsonDoJumpIdKey)) {
_doJumpId = v2Json[_jsonDoJumpIdKey].toInt();
}
setIsCurrentItem(false);
setSequenceNumber(json[_jsonIdKey].toInt());
setParam1(json[_jsonParam1Key].toDouble());
setParam2(json[_jsonParam2Key].toDouble());
setParam3(json[_jsonParam3Key].toDouble());
setParam4(json[_jsonParam4Key].toDouble());
setAutoContinue(json[_jsonAutoContinueKey].toBool());
setSequenceNumber(sequenceNumber);
setAutoContinue(v2Json[_jsonAutoContinueKey].toBool());
setParam1(rgParams[0].toDouble());
setParam2(rgParams[1].toDouble());
setParam3(rgParams[2].toDouble());
setParam4(rgParams[3].toDouble());
return true;
}
......
......@@ -74,6 +74,7 @@ public:
double param6 (void) const { return _param6Fact.rawValue().toDouble(); }
double param7 (void) const { return _param7Fact.rawValue().toDouble(); }
QGeoCoordinate coordinate (void) const;
int doJumpId (void) const { return _doJumpId; }
void setCommand (MAV_CMD command);
void setSequenceNumber (int sequenceNumber);
......@@ -91,7 +92,7 @@ public:
void save(QJsonObject& json) const;
bool load(QTextStream &loadStream);
bool load(const QJsonObject& json, QString& errorString);
bool load(const QJsonObject& json, int sequenceNumber, QString& errorString);
bool relativeAltitude(void) const { return frame() == MAV_FRAME_GLOBAL_RELATIVE_ALT; }
......@@ -100,8 +101,11 @@ signals:
void sequenceNumberChanged (int sequenceNumber);
private:
int _sequenceNumber;
bool _isCurrentItem;
bool _convertJsonV1ToV2(const QJsonObject& json, QJsonObject& v2Json, QString& errorString);
int _sequenceNumber;
int _doJumpId;
bool _isCurrentItem;
Fact _autoContinueFact;
Fact _commandFact;
......@@ -115,17 +119,18 @@ private:
Fact _param7Fact;
// Keys for Json save
static const char* _itemType;
static const char* _jsonTypeKey;
static const char* _jsonIdKey;
static const char* _jsonFrameKey;
static const char* _jsonCommandKey;
static const char* _jsonAutoContinueKey;
static const char* _jsonCoordinateKey;
static const char* _jsonParamsKey;
static const char* _jsonDoJumpIdKey;
// Deprecated V1 format keys
static const char* _jsonParam1Key;
static const char* _jsonParam2Key;
static const char* _jsonParam3Key;
static const char* _jsonParam4Key;
static const char* _jsonAutoContinueKey;
static const char* _jsonCoordinateKey;
friend class SurveyMissionItem;
friend class SimpleMissionItem;
......
This diff is collapsed.
......@@ -29,12 +29,15 @@ private slots:
void _testFactSignals(void);
void _testLoadFromStream(void);
void _testSimpleLoadFromStream(void);
void _testLoadFromJson(void);
void _testLoadFromJsonV1(void);
void _testLoadFromJsonV2(void);
void _testSimpleLoadFromJson(void);
void _testSaveToJson(void);
private:
void _checkExpectedMissionItem(const MissionItem& missionItem);
int _seq = 10;
};
#endif
......@@ -75,8 +75,13 @@ bool RallyPointController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorS
{
QJsonObject json = jsonDoc.object();
int fileMajorVersion, fileMinorVersion;
if (!JsonHelper::validateQGCJsonFile(json, _jsonFileTypeValue, 1 /* supportedMajorVersion */, 0 /* supportedMinorVersion */, fileMajorVersion, fileMinorVersion, errorString)) {
int fileVersion;
if (!JsonHelper::validateQGCJsonFile(json,
_jsonFileTypeValue, // expected file type
1, // minimum supported version
1, // maximum supported version
fileVersion,
errorString)) {
return false;
}
......@@ -166,7 +171,7 @@ void RallyPointController::saveToFile(const QString& filename)
QJsonObject jsonObject;
jsonObject[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue;
jsonObject[JsonHelper::jsonVersionKey] = QStringLiteral("1.0");
jsonObject[JsonHelper::jsonVersionKey] = 1;
jsonObject[JsonHelper::jsonGroundStationKey] = JsonHelper::jsonGroundStationValue;
QJsonArray rgPoints;
......
......@@ -18,14 +18,14 @@
#include "MissionCommandTree.h"
#include "MissionCommandUIInfo.h"
const double SimpleMissionItem::defaultAltitude = 50.0;
const double SimpleMissionItem::defaultAltitude = 50.0;
FactMetaData* SimpleMissionItem::_altitudeMetaData = NULL;
FactMetaData* SimpleMissionItem::_commandMetaData = NULL;
FactMetaData* SimpleMissionItem::_defaultParamMetaData = NULL;
FactMetaData* SimpleMissionItem::_frameMetaData = NULL;
FactMetaData* SimpleMissionItem::_latitudeMetaData = NULL;
FactMetaData* SimpleMissionItem::_longitudeMetaData = NULL;
FactMetaData* SimpleMissionItem::_altitudeMetaData = NULL;
FactMetaData* SimpleMissionItem::_commandMetaData = NULL;
FactMetaData* SimpleMissionItem::_defaultParamMetaData = NULL;
FactMetaData* SimpleMissionItem::_frameMetaData = NULL;
FactMetaData* SimpleMissionItem::_latitudeMetaData = NULL;
FactMetaData* SimpleMissionItem::_longitudeMetaData = NULL;
struct EnumInfo_s {
const char * label;
......@@ -248,9 +248,9 @@ bool SimpleMissionItem::load(QTextStream &loadStream)
return _missionItem.load(loadStream);
}
bool SimpleMissionItem::load(const QJsonObject& json, QString& errorString)
bool SimpleMissionItem::load(const QJsonObject& json, int sequenceNumber, QString& errorString)
{
return _missionItem.load(json, errorString);
return _missionItem.load(json, sequenceNumber, errorString);
}
bool SimpleMissionItem::isStandaloneCoordinate(void) const
......
......@@ -71,7 +71,7 @@ public:
void setDistance (double distance);
bool load(QTextStream &loadStream);
bool load(const QJsonObject& json, QString& errorString);
bool load(const QJsonObject& json, int sequenceNumber, QString& errorString);
bool relativeAltitude(void) { return _missionItem.frame() == MAV_FRAME_GLOBAL_RELATIVE_ALT; }
......
......@@ -17,9 +17,9 @@
QGC_LOGGING_CATEGORY(SurveyMissionItemLog, "SurveyMissionItemLog")
const char* SurveyMissionItem::_jsonTypeKey = "type";
const char* SurveyMissionItem::jsonComplexItemTypeValue = "survey";
const char* SurveyMissionItem::_jsonPolygonObjectKey = "polygon";
const char* SurveyMissionItem::_jsonIdKey = "id";
const char* SurveyMissionItem::_jsonGridObjectKey = "grid";
const char* SurveyMissionItem::_jsonGridAltitudeKey = "altitude";
const char* SurveyMissionItem::_jsonGridAltitudeRelativeKey = "relativeAltitude";
......@@ -30,7 +30,7 @@ const char* SurveyMissionItem::_jsonCameraTriggerKey = "cameraTrigg
const char* SurveyMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance";
const char* SurveyMissionItem::_jsonGroundResolutionKey = "groundResolution";
const char* SurveyMissionItem::_jsonFrontalOverlapKey = "imageFrontalOverlap";
const char* SurveyMissionItem::_jsonSideOverlapKey = "imageSizeOverlap";
const char* SurveyMissionItem::_jsonSideOverlapKey = "imageSideOverlap";
const char* SurveyMissionItem::_jsonCameraSensorWidthKey = "sensorWidth";
const char* SurveyMissionItem::_jsonCameraSensorHeightKey = "sensorHeight";
const char* SurveyMissionItem::_jsonCameraResolutionWidthKey = "resolutionWidth";
......@@ -56,8 +56,6 @@ const char* SurveyMissionItem::_cameraResolutionWidthFactName = "Camera reso
const char* SurveyMissionItem::_cameraResolutionHeightFactName = "Camera resolution height";
const char* SurveyMissionItem::_cameraFocalLengthFactName = "Focal length";
const char* SurveyMissionItem::_complexType = "survey";
QMap<QString, FactMetaData*> SurveyMissionItem::_metaDataMap;
SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
......@@ -239,12 +237,12 @@ void SurveyMissionItem::setDirty(bool dirty)
void SurveyMissionItem::save(QJsonObject& saveObject) const
{
saveObject[JsonHelper::jsonVersionKey] = 2;
saveObject[_jsonTypeKey] = _complexType;
saveObject[_jsonIdKey] = sequenceNumber();
saveObject[_jsonCameraTriggerKey] = _cameraTrigger;
saveObject[_jsonManualGridKey] = _manualGrid;
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitude;
saveObject[JsonHelper::jsonVersionKey] = 3;
saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
saveObject[_jsonCameraTriggerKey] = _cameraTrigger;
saveObject[_jsonManualGridKey] = _manualGrid;
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitude;
if (_cameraTrigger) {
saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble();
......@@ -306,98 +304,114 @@ void SurveyMissionItem::_clear(void)
}
bool SurveyMissionItem::load(const QJsonObject& complexObject, QString& errorString)
bool SurveyMissionItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
{
struct jsonKeyInfo_s {
const char* key;
QJsonValue::Type type;
bool required;
};
QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
{ _jsonTypeKey, QJsonValue::String, true },
{ _jsonPolygonObjectKey, QJsonValue::Array, true },
{ _jsonIdKey, QJsonValue::Double, true },
{ _jsonGridObjectKey, QJsonValue::Object, true },
{ _jsonCameraObjectKey, QJsonValue::Object, false },
{ _jsonCameraTriggerKey, QJsonValue::Bool, true },
{ _jsonCameraTriggerDistanceKey, QJsonValue::Double, false },
{ _jsonManualGridKey, QJsonValue::Bool, true },
{ _jsonFixedValueIsAltitudeKey, QJsonValue::Bool, true },
};
QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
{ _jsonGridAltitudeKey, QJsonValue::Double, true },
{ _jsonGridAltitudeRelativeKey, QJsonValue::Bool, true },
{ _jsonGridAngleKey, QJsonValue::Double, true },
{ _jsonGridSpacingKey, QJsonValue::Double, true },
{ _jsonTurnaroundDistKey, QJsonValue::Double, true },
};
QJsonObject v2Object = complexObject;
QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
{ _jsonGroundResolutionKey, QJsonValue::Double, true },
{ _jsonFrontalOverlapKey, QJsonValue::Double, true },
{ _jsonSideOverlapKey, QJsonValue::Double, true },
{ _jsonCameraSensorWidthKey, QJsonValue::Double, true },
{ _jsonCameraSensorHeightKey, QJsonValue::Double, true },
{ _jsonCameraResolutionWidthKey, QJsonValue::Double, true },
{ _jsonCameraResolutionHeightKey, QJsonValue::Double, true },
{ _jsonCameraFocalLengthKey, QJsonValue::Double, true },
{ _jsonCameraNameKey, QJsonValue::String, true },
{ _jsonCameraOrientationLandscapeKey, QJsonValue::Bool, true },
// We need to pull version first to determine what validation/conversion needs to be performed.
QList<JsonHelper::KeyValidateInfo> versionKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
};
if (!JsonHelper::validateKeys(complexObject, mainKeyInfoList, errorString)) {
if (!JsonHelper::validateKeys(v2Object, versionKeyInfoList, errorString)) {
return false;
}
if (!JsonHelper::validateKeys(complexObject[_jsonGridObjectKey].toObject(), gridKeyInfoList, errorString)) {
int version = v2Object[JsonHelper::jsonVersionKey].toInt();
if (version != 2 && version != 3) {
errorString = tr("QGroundControl does not support this version of survey items");
return false;
}
if (version == 2) {
// Convert to v3
if (v2Object.contains(VisualMissionItem::jsonTypeKey) && v2Object[VisualMissionItem::jsonTypeKey].toString() == QStringLiteral("survey")) {
v2Object[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
v2Object[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
}
}
// Version check
if (complexObject[JsonHelper::jsonVersionKey].toInt() != 2) {
errorString = tr("QGroundControl does not support this version of survey items");
QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
{ ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true },
{ _jsonPolygonObjectKey, QJsonValue::Array, true },
{ _jsonGridObjectKey, QJsonValue::Object, true },
{ _jsonCameraObjectKey, QJsonValue::Object, false },
{ _jsonCameraTriggerKey, QJsonValue::Bool, true },
{ _jsonCameraTriggerDistanceKey, QJsonValue::Double, false },
{ _jsonManualGridKey, QJsonValue::Bool, true },
{ _jsonFixedValueIsAltitudeKey, QJsonValue::Bool, true },
};
if (!JsonHelper::validateKeys(v2Object, mainKeyInfoList, errorString)) {
return false;
}
QString complexType = complexObject[_jsonTypeKey].toString();
if (complexType != _complexType) {
errorString = tr("QGroundControl does not support loading this complex mission item type: %1").arg(complexType);
QString itemType = v2Object[VisualMissionItem::jsonTypeKey].toString();
QString complexType = v2Object[ComplexMissionItem::jsonComplexItemTypeKey].toString();
if (itemType != VisualMissionItem::jsonTypeComplexItemValue || complexType != jsonComplexItemTypeValue) {
errorString = tr("QGroundControl does not support loading this complex mission item type: %1:2").arg(itemType).arg(complexType);
return false;
}
_clear();
setSequenceNumber(complexObject[_jsonIdKey].toInt());
setSequenceNumber(sequenceNumber);
_manualGrid = complexObject[_jsonManualGridKey].toBool(true);
_cameraTrigger = complexObject[_jsonCameraTriggerKey].toBool(false);
_fixedValueIsAltitude = complexObject[_jsonFixedValueIsAltitudeKey].toBool(true);
_gridAltitudeRelative = complexObject[_jsonGridAltitudeRelativeKey].toBool(true);
QJsonObject gridObject = complexObject[_jsonGridObjectKey].toObject();
_manualGrid = v2Object[_jsonManualGridKey].toBool(true);
_cameraTrigger = v2Object[_jsonCameraTriggerKey].toBool(false);
_fixedValueIsAltitude = v2Object[_jsonFixedValueIsAltitudeKey].toBool(true);
_gridAltitudeRelative = v2Object[_jsonGridAltitudeRelativeKey].toBool(true);
QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
{ _jsonGridAltitudeKey, QJsonValue::Double, true },
{ _jsonGridAltitudeRelativeKey, QJsonValue::Bool, true },
{ _jsonGridAngleKey, QJsonValue::Double, true },
{ _jsonGridSpacingKey, QJsonValue::Double, true },
{ _jsonTurnaroundDistKey, QJsonValue::Double, true },
};
QJsonObject gridObject = v2Object[_jsonGridObjectKey].toObject();
if (!JsonHelper::validateKeys(gridObject, gridKeyInfoList, errorString)) {
return false;
}
_gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (gridObject[_jsonGridSpacingKey].toDouble());
_turnaroundDistFact.setRawValue (gridObject[_jsonTurnaroundDistKey].toDouble());
if (_cameraTrigger) {
if (!complexObject.contains(_jsonCameraTriggerDistanceKey)) {
if (!v2Object.contains(_jsonCameraTriggerDistanceKey)) {
errorString = tr("%1 but %2 is missing").arg("cameraTrigger = true").arg("cameraTriggerDistance");
return false;
}
_cameraTriggerDistanceFact.setRawValue(complexObject[_jsonCameraTriggerDistanceKey].toDouble());
_cameraTriggerDistanceFact.setRawValue(v2Object[_jsonCameraTriggerDistanceKey].toDouble());
}
if (!_manualGrid) {
if (!complexObject.contains(_jsonCameraObjectKey)) {
if (!v2Object.contains(_jsonCameraObjectKey)) {
errorString = tr("%1 but %2 object is missing").arg("manualGrid = false").arg("camera");
return false;
}
QJsonObject cameraObject = complexObject[_jsonCameraObjectKey].toObject();
QJsonObject cameraObject = v2Object[_jsonCameraObjectKey].toObject();
// Older code had typo on "imageSideOverlap" incorrectly being "imageSizeOverlap"
QString incorrectImageSideOverlap = "imageSizeOverlap";
if (cameraObject.contains(incorrectImageSideOverlap)) {
cameraObject[_jsonSideOverlapKey] = cameraObject[incorrectImageSideOverlap];
cameraObject.remove(incorrectImageSideOverlap);
}
QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
{ _jsonGroundResolutionKey, QJsonValue::Double, true },
{ _jsonFrontalOverlapKey, QJsonValue::Double, true },
{ _jsonSideOverlapKey, QJsonValue::Double, true },
{ _jsonCameraSensorWidthKey, QJsonValue::Double, true },
{ _jsonCameraSensorHeightKey, QJsonValue::Double, true },
{ _jsonCameraResolutionWidthKey, QJsonValue::Double, true },
{ _jsonCameraResolutionHeightKey, QJsonValue::Double, true },
{ _jsonCameraFocalLengthKey, QJsonValue::Double, true },
{ _jsonCameraNameKey, QJsonValue::String, true },
{ _jsonCameraOrientationLandscapeKey, QJsonValue::Bool, true },
};
if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList, errorString)) {
return false;
}
......@@ -416,7 +430,7 @@ bool SurveyMissionItem::load(const QJsonObject& complexObject, QString& errorStr
}
// Polygon shape
QJsonArray polygonArray(complexObject[_jsonPolygonObjectKey].toArray());
QJsonArray polygonArray(v2Object[_jsonPolygonObjectKey].toArray());
for (int i=0; i<polygonArray.count(); i++) {
const QJsonValue& pointValue = polygonArray[i];
......
......@@ -78,7 +78,7 @@ public:
double complexDistance (void) const final { return _surveyDistance; }
int lastSequenceNumber (void) const final;
QmlObjectListModel* getMissionItems (void) const final;
bool load (const QJsonObject& complexObject, QString& errorString) final;
bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final;
double greatestDistanceTo (const QGeoCoordinate &other) const final;
// Overrides from VisualMissionItem
......@@ -104,6 +104,8 @@ public:
void setTurnaroundDist (double dist) { _turnaroundDistFact.setRawValue(dist); }
void save (QJsonObject& saveObject) const final;
static const char* jsonComplexItemTypeValue;
signals:
void polygonPathChanged (void);
void altitudeChanged (double altitude);
......@@ -173,9 +175,7 @@ private:
static QMap<QString, FactMetaData*> _metaDataMap;
static const char* _jsonTypeKey;
static const char* _jsonPolygonObjectKey;
static const char* _jsonIdKey;
static const char* _jsonGridObjectKey;
static const char* _jsonGridAltitudeKey;
static const char* _jsonGridAltitudeRelativeKey;
......@@ -212,8 +212,6 @@ private:
static const char* _cameraResolutionWidthFactName;
static const char* _cameraResolutionHeightFactName;
static const char* _cameraFocalLengthFactName;
static const char* _complexType;
};
#endif
......@@ -16,6 +16,10 @@
#include "QGCApplication.h"
#include "JsonHelper.h"
const char* VisualMissionItem::jsonTypeKey = "type";
const char* VisualMissionItem::jsonTypeSimpleItemValue = "SimpleItem";
const char* VisualMissionItem::jsonTypeComplexItemValue = "ComplexItem";
VisualMissionItem::VisualMissionItem(Vehicle* vehicle, QObject* parent)
: QObject(parent)
, _vehicle(vehicle)
......
......@@ -123,6 +123,10 @@ public:
/// @param saveObject Save the item to this json object
virtual void save(QJsonObject& saveObject) const = 0;
static const char* jsonTypeKey; ///< Json file attribute which specifies the item type
static const char* jsonTypeSimpleItemValue; ///< Item type is MISSION_ITEM
static const char* jsonTypeComplexItemValue; ///< Item type is Complex Item
signals:
void altDifferenceChanged (double altDifference);
void altPercentChanged (double altPercent);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment