diff --git a/src/FactSystem/FactGroup.cc b/src/FactSystem/FactGroup.cc
index 517e948f4878ec8eb84efc76144d106b4a74d33c..436f9d0e0253aec84bc7711f7dfbfffddb2b0a7f 100644
--- a/src/FactSystem/FactGroup.cc
+++ b/src/FactSystem/FactGroup.cc
@@ -37,7 +37,7 @@ FactGroup::FactGroup(int updateRateMsecs, QObject* parent, bool ignoreCamelCase)
     QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
 }
 
-void FactGroup::_loadFromJsonArray(const QJsonObject jsonArray)
+void FactGroup::_loadFromJsonArray(const QJsonArray jsonArray)
 {
     QMap<QString, QString> defineMap;
     _nameToFactMetaDataMap = FactMetaData::createMapFromJsonArray(jsonArray, defineMap, this);
diff --git a/src/FactSystem/FactGroup.h b/src/FactSystem/FactGroup.h
index f3b3981c6ea10f38ec3fb12c3689b3d7e23b775a..114fb44f4e0dfd82322082438f0528052a17411f 100644
--- a/src/FactSystem/FactGroup.h
+++ b/src/FactSystem/FactGroup.h
@@ -64,7 +64,7 @@ protected slots:
 protected:
     void _addFact               (Fact* fact, const QString& name);
     void _addFactGroup          (FactGroup* factGroup, const QString& name);
-    void _loadFromJsonArray     (const QJsonObject jsonArray);
+    void _loadFromJsonArray     (const QJsonArray jsonArray);
     void _setTelemetryAvailable (bool telemetryAvailable);
 
     int  _updateRateMSecs;   ///< Update rate for Fact::valueChanged signals, 0: immediate update
diff --git a/src/FactSystem/FactMetaData.cc b/src/FactSystem/FactMetaData.cc
index 0ac10c22edd477bb37e6de7124db84155ca09b42..7e1c95a8ac5fe54e58428c2dd3b4ccb65f0ab3e6 100644
--- a/src/FactSystem/FactMetaData.cc
+++ b/src/FactSystem/FactMetaData.cc
@@ -1448,7 +1448,7 @@ QMap<QString, FactMetaData*> FactMetaData::createMapFromJsonFile(const QString&
         return metaDataMap;
     }
 
-    QJsonObject factArray;
+    QJsonArray factArray;
     QMap<QString /* define name */, QString /* define value */> defineMap;
 
     QList<JsonHelper::KeyValidateInfo> keyInfoList = {
@@ -1466,7 +1466,7 @@ QMap<QString, FactMetaData*> FactMetaData::createMapFromJsonFile(const QString&
     return createMapFromJsonArray(factArray, defineMap, metaDataParent);
 }
 
-QMap<QString, FactMetaData*> FactMetaData::createMapFromJsonArray(const QJsonObject jsonArray, QMap<QString, QString>& defineMap, QObject* metaDataParent)
+QMap<QString, FactMetaData*> FactMetaData::createMapFromJsonArray(const QJsonArray jsonArray, QMap<QString, QString>& defineMap, QObject* metaDataParent)
 {
     QMap<QString, FactMetaData*> metaDataMap;
     for (int i=0; i<jsonArray.count(); i++) {
@@ -1554,7 +1554,7 @@ bool FactMetaData::_parseValuesArray(const QJsonObject& jsonObject, QStringList&
         { _enumValuesArrayValueJsonKey,         QJsonValue::Double, true },
     };
 
-    const QJsonObject& rgValueDescription = jsonObject[_enumValuesArrayJsonKey].toArray();
+    const QJsonArray& rgValueDescription = jsonObject[_enumValuesArrayJsonKey].toArray();
     for (int i=0; i<rgValueDescription.count(); i++) {
         if (rgValueDescription[i].type() != QJsonValue::Object) {
             errorString = QStringLiteral("Value at index %1 in \"values\" array is not an object.").arg(i);
@@ -1589,7 +1589,7 @@ bool FactMetaData::_parseBitmaskArray(const QJsonObject& jsonObject, QStringList
         { _enumBitmaskArrayIndexJsonKey,         QJsonValue::Double, true },
     };
 
-    const QJsonObject& rgValueDescription = jsonObject[_enumBitmaskArrayJsonKey].toArray();
+    const QJsonArray& rgValueDescription = jsonObject[_enumBitmaskArrayJsonKey].toArray();
     for (int i=0; i<rgValueDescription.count(); i++) {
         if (rgValueDescription[i].type() != QJsonValue::Object) {
             errorString = QStringLiteral("Value at index %1 in \"values\" array is not an object.").arg(i);
diff --git a/src/FactSystem/FactMetaData.h b/src/FactSystem/FactMetaData.h
index 804cd59b498d1f195bfabdd9d167ff29cb98ffc3..bcc2f74bfafec7265255e403e3992b5b2e9ccf28 100644
--- a/src/FactSystem/FactMetaData.h
+++ b/src/FactSystem/FactMetaData.h
@@ -57,7 +57,7 @@ public:
     typedef QMap<QString, QString> DefineMap_t;
 
     static QMap<QString, FactMetaData*> createMapFromJsonFile(const QString& jsonFilename, QObject* metaDataParent);
-    static QMap<QString, FactMetaData*> createMapFromJsonArray(const QJsonObject jsonArray, DefineMap_t& defineMap, QObject* metaDataParent);
+    static QMap<QString, FactMetaData*> createMapFromJsonArray(const QJsonArray jsonArray, DefineMap_t& defineMap, QObject* metaDataParent);
 
     static FactMetaData* createFromJsonObject(const QJsonObject& json, QMap<QString, QString>& defineMap, QObject* metaDataParent);
 
diff --git a/src/FactSystemFactGroup.cc b/src/FactSystemFactGroup.cc
new file mode 100644
index 0000000000000000000000000000000000000000..436f9d0e0253aec84bc7711f7dfbfffddb2b0a7f
--- /dev/null
+++ b/src/FactSystemFactGroup.cc
@@ -0,0 +1,194 @@
+/****************************************************************************
+ *
+ * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+
+#include "FactGroup.h"
+#include "JsonHelper.h"
+
+#include <QJsonDocument>
+#include <QJsonParseError>
+#include <QJsonArray>
+#include <QDebug>
+#include <QFile>
+#include <QQmlEngine>
+
+FactGroup::FactGroup(int updateRateMsecs, const QString& metaDataFile, QObject* parent, bool ignoreCamelCase)
+    : QObject(parent)
+    , _updateRateMSecs(updateRateMsecs)
+    , _ignoreCamelCase(ignoreCamelCase)
+{
+    _setupTimer();
+    _nameToFactMetaDataMap = FactMetaData::createMapFromJsonFile(metaDataFile, this);
+    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+}
+
+FactGroup::FactGroup(int updateRateMsecs, QObject* parent, bool ignoreCamelCase)
+    : QObject(parent)
+    , _updateRateMSecs(updateRateMsecs)
+    , _ignoreCamelCase(ignoreCamelCase)
+{
+    _setupTimer();
+    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+}
+
+void FactGroup::_loadFromJsonArray(const QJsonArray jsonArray)
+{
+    QMap<QString, QString> defineMap;
+    _nameToFactMetaDataMap = FactMetaData::createMapFromJsonArray(jsonArray, defineMap, this);
+}
+
+void FactGroup::_setupTimer()
+{
+    if (_updateRateMSecs > 0) {
+        connect(&_updateTimer, &QTimer::timeout, this, &FactGroup::_updateAllValues);
+        _updateTimer.setSingleShot(false);
+        _updateTimer.setInterval(_updateRateMSecs);
+        _updateTimer.start();
+    }
+}
+
+bool FactGroup::factExists(const QString& name)
+{
+    if (name.contains(".")) {
+        QStringList parts = name.split(".");
+        if (parts.count() != 2) {
+            qWarning() << "Only single level of hierarchy supported";
+            return false;
+        }
+
+        FactGroup * factGroup = getFactGroup(parts[0]);
+        if (!factGroup) {
+            qWarning() << "Unknown FactGroup" << parts[0];
+            return false;
+        }
+
+        return factGroup->factExists(parts[1]);
+    }
+
+    QString camelCaseName = _ignoreCamelCase ? name : _camelCase(name);
+
+    return _nameToFactMap.contains(camelCaseName);
+}
+
+Fact* FactGroup::getFact(const QString& name)
+{
+    if (name.contains(".")) {
+        QStringList parts = name.split(".");
+        if (parts.count() != 2) {
+            qWarning() << "Only single level of hierarchy supported";
+            return nullptr;
+        }
+
+        FactGroup * factGroup = getFactGroup(parts[0]);
+        if (!factGroup) {
+            qWarning() << "Unknown FactGroup" << parts[0];
+            return nullptr;
+        }
+
+        return factGroup->getFact(parts[1]);
+    }
+
+    Fact*   fact =          nullptr;
+    QString camelCaseName = _ignoreCamelCase ? name : _camelCase(name);
+
+    if (_nameToFactMap.contains(camelCaseName)) {
+        fact = _nameToFactMap[camelCaseName];
+        QQmlEngine::setObjectOwnership(fact, QQmlEngine::CppOwnership);
+    } else {
+        qWarning() << "Unknown Fact" << camelCaseName;
+    }
+
+    return fact;
+}
+
+FactGroup* FactGroup::getFactGroup(const QString& name)
+{
+    FactGroup*  factGroup = nullptr;
+    QString     camelCaseName = _ignoreCamelCase ? name : _camelCase(name);
+
+    if (_nameToFactGroupMap.contains(camelCaseName)) {
+        factGroup = _nameToFactGroupMap[camelCaseName];
+        QQmlEngine::setObjectOwnership(factGroup, QQmlEngine::CppOwnership);
+    } else {
+        qWarning() << "Unknown FactGroup" << camelCaseName;
+    }
+
+    return factGroup;
+}
+
+void FactGroup::_addFact(Fact* fact, const QString& name)
+{
+    if (_nameToFactMap.contains(name)) {
+        qWarning() << "Duplicate Fact" << name;
+        return;
+    }
+
+    fact->setSendValueChangedSignals(_updateRateMSecs == 0);
+    if (_nameToFactMetaDataMap.contains(name)) {
+        fact->setMetaData(_nameToFactMetaDataMap[name], true /* setDefaultFromMetaData */);
+    }
+    _nameToFactMap[name] = fact;
+    _factNames.append(name);
+
+    emit factNamesChanged();
+}
+
+void FactGroup::_addFactGroup(FactGroup* factGroup, const QString& name)
+{
+    if (_nameToFactGroupMap.contains(name)) {
+        qWarning() << "Duplicate FactGroup" << name;
+        return;
+    }
+
+    _nameToFactGroupMap[name] = factGroup;
+
+    emit factGroupNamesChanged();
+}
+
+void FactGroup::_updateAllValues(void)
+{
+    for(Fact* fact: _nameToFactMap) {
+        fact->sendDeferredValueChangedSignal();
+    }
+}
+
+void FactGroup::setLiveUpdates(bool liveUpdates)
+{
+    if (_updateTimer.interval() == 0) {
+        return;
+    }
+
+    if (liveUpdates) {
+        _updateTimer.stop();
+    } else {
+        _updateTimer.start();
+    }
+    for(Fact* fact: _nameToFactMap) {
+        fact->setSendValueChangedSignals(liveUpdates);
+    }
+}
+
+
+QString FactGroup::_camelCase(const QString& text)
+{
+    return text[0].toLower() + text.right(text.length() - 1);
+}
+
+void FactGroup::handleMessage(Vehicle* /* vehicle */, mavlink_message_t& /* message */)
+{
+    // Default implementation does nothing
+}
+
+void FactGroup::_setTelemetryAvailable (bool telemetryAvailable)
+{
+    if (telemetryAvailable != _telemetryAvailable) {
+        _telemetryAvailable = telemetryAvailable;
+        emit telemetryAvailableChanged(_telemetryAvailable);
+    }
+}
diff --git a/src/JsonHelper.cc b/src/JsonHelper.cc
index d701185b66524fcd5b29e5e169b65272e40038d3..82579c829b7197a8d29e5bc6bfe48b6f18eb2f92 100644
--- a/src/JsonHelper.cc
+++ b/src/JsonHelper.cc
@@ -8,551 +8,518 @@
  ****************************************************************************/
 
 #include "JsonHelper.h"
-#include "FactMetaData.h"
-#include "MissionCommandList.h"
-#include "QGCApplication.h"
 #include "QGCQGeoCoordinate.h"
 #include "QmlObjectListModel.h"
+#include "MissionCommandList.h"
+#include "FactMetaData.h"
+#include "QGCApplication.h"
 
-#include <QFile>
 #include <QJsonArray>
 #include <QJsonParseError>
 #include <QObject>
 #include <QRegularExpression>
 #include <QRegularExpressionMatch>
+#include <QFile>
 #include <QTranslator>
 
-const char *JsonHelper::jsonVersionKey = "version";
-const char *JsonHelper::jsonGroundStationKey = "groundStation";
-const char *JsonHelper::jsonGroundStationValue = "QGroundControl";
-const char *JsonHelper::jsonFileTypeKey = "fileType";
-const char *JsonHelper::_translateKeysKey = "translateKeys";
-const char *JsonHelper::_arrayIDKeysKey = "_arrayIDKeys";
-
-bool JsonHelper::validateRequiredKeys(const QJsonObject &jsonObject,
-                                      const QStringList &keys,
-                                      QString &errorString) {
-  QString missingKeys;
-
-  foreach (const QString &key, keys) {
-    if (!jsonObject.contains(key)) {
-      if (!missingKeys.isEmpty()) {
-        missingKeys += QStringLiteral(", ");
-      }
-      missingKeys += key;
-    }
-  }
-
-  if (missingKeys.count() != 0) {
-    errorString = QObject::tr("The following required keys are missing: %1")
-                      .arg(missingKeys);
-    return false;
-  }
-
-  return true;
+const char* JsonHelper::jsonVersionKey                      = "version";
+const char* JsonHelper::jsonGroundStationKey                = "groundStation";
+const char* JsonHelper::jsonGroundStationValue              = "QGroundControl";
+const char* JsonHelper::jsonFileTypeKey                     = "fileType";
+const char* JsonHelper::_translateKeysKey                   = "translateKeys";
+const char* JsonHelper::_arrayIDKeysKey                     = "_arrayIDKeys";
+
+bool JsonHelper::validateRequiredKeys(const QJsonObject& jsonObject, const QStringList& keys, QString& errorString)
+{
+    QString missingKeys;
+
+    foreach(const QString& key, keys) {
+        if (!jsonObject.contains(key)) {
+            if (!missingKeys.isEmpty()) {
+                missingKeys += QStringLiteral(", ");
+            }
+            missingKeys += key;
+        }
+    }
+
+    if (missingKeys.count() != 0) {
+        errorString = QObject::tr("The following required keys are missing: %1").arg(missingKeys);
+        return false;
+    }
+
+    return true;
 }
 
-bool JsonHelper::_loadGeoCoordinate(const QJsonValue &jsonValue,
-                                    bool altitudeRequired,
-                                    QGeoCoordinate &coordinate,
-                                    QString &errorString, bool geoJsonFormat) {
-  if (!jsonValue.isArray()) {
-    errorString = QObject::tr("value for coordinate is not array");
-    return false;
-  }
-
-  QJsonObject coordinateArray = jsonValue.toArray();
-  int requiredCount = altitudeRequired ? 3 : 2;
-  if (coordinateArray.count() != requiredCount) {
-    errorString = QObject::tr("Coordinate array must contain %1 values")
-                      .arg(requiredCount);
-    return false;
-  }
-
-  foreach (const QJsonValue &jsonValue, coordinateArray) {
-    if (jsonValue.type() != QJsonValue::Double &&
-        jsonValue.type() != QJsonValue::Null) {
-      errorString =
-          QObject::tr(
-              "Coordinate array may only contain double values, found: %1")
-              .arg(jsonValue.type());
-      return false;
-    }
-  }
-
-  if (geoJsonFormat) {
-    coordinate = QGeoCoordinate(coordinateArray[1].toDouble(),
-                                coordinateArray[0].toDouble());
-  } else {
-    coordinate = QGeoCoordinate(possibleNaNJsonValue(coordinateArray[0]),
-                                possibleNaNJsonValue(coordinateArray[1]));
-  }
-  if (altitudeRequired) {
-    coordinate.setAltitude(possibleNaNJsonValue(coordinateArray[2]));
-  }
-
-  return true;
+bool JsonHelper::_loadGeoCoordinate(const QJsonValue&   jsonValue,
+                                    bool                altitudeRequired,
+                                    QGeoCoordinate&     coordinate,
+                                    QString&            errorString,
+                                    bool                geoJsonFormat)
+{
+    if (!jsonValue.isArray()) {
+        errorString = QObject::tr("value for coordinate is not array");
+        return false;
+    }
+
+    QJsonArray coordinateArray = jsonValue.toArray();
+    int requiredCount = altitudeRequired ? 3 : 2;
+    if (coordinateArray.count() != requiredCount) {
+        errorString = QObject::tr("Coordinate array must contain %1 values").arg(requiredCount);
+        return false;
+    }
+
+    foreach(const QJsonValue& jsonValue, coordinateArray) {
+        if (jsonValue.type() != QJsonValue::Double && jsonValue.type() != QJsonValue::Null) {
+            errorString = QObject::tr("Coordinate array may only contain double values, found: %1").arg(jsonValue.type());
+            return false;
+        }
+    }
+
+    if (geoJsonFormat) {
+        coordinate = QGeoCoordinate(coordinateArray[1].toDouble(), coordinateArray[0].toDouble());
+    } else {
+        coordinate = QGeoCoordinate(possibleNaNJsonValue(coordinateArray[0]), possibleNaNJsonValue(coordinateArray[1]));
+    }
+    if (altitudeRequired) {
+        coordinate.setAltitude(possibleNaNJsonValue(coordinateArray[2]));
+    }
+
+    return true;
 }
 
-void JsonHelper::_saveGeoCoordinate(const QGeoCoordinate &coordinate,
-                                    bool writeAltitude, QJsonValue &jsonValue,
-                                    bool geoJsonFormat) {
-  QJsonObject coordinateArray;
-
-  if (geoJsonFormat) {
-    coordinateArray << coordinate.longitude() << coordinate.latitude();
-  } else {
-    coordinateArray << coordinate.latitude() << coordinate.longitude();
-  }
-  if (writeAltitude) {
-    coordinateArray << coordinate.altitude();
-  }
-
-  jsonValue = QJsonValue(coordinateArray);
+void JsonHelper::_saveGeoCoordinate(const QGeoCoordinate&   coordinate,
+                                    bool                    writeAltitude,
+                                    QJsonValue&             jsonValue,
+                                    bool                    geoJsonFormat)
+{
+    QJsonArray coordinateArray;
+
+    if (geoJsonFormat) {
+        coordinateArray << coordinate.longitude() << coordinate.latitude();
+    } else {
+        coordinateArray << coordinate.latitude() << coordinate.longitude();
+    }
+    if (writeAltitude) {
+        coordinateArray << coordinate.altitude();
+    }
+
+    jsonValue = QJsonValue(coordinateArray);
 }
 
-bool JsonHelper::loadGeoCoordinate(const QJsonValue &jsonValue,
-                                   bool altitudeRequired,
-                                   QGeoCoordinate &coordinate,
-                                   QString &errorString, bool geoJsonFormat) {
-  return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate,
-                            errorString, geoJsonFormat);
+bool JsonHelper::loadGeoCoordinate(const QJsonValue&    jsonValue,
+                                   bool                 altitudeRequired,
+                                   QGeoCoordinate&      coordinate,
+                                   QString&             errorString,
+                                   bool                 geoJsonFormat)
+{
+    return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate, errorString, geoJsonFormat);
 }
 
-void JsonHelper::saveGeoCoordinate(const QGeoCoordinate &coordinate,
-                                   bool writeAltitude, QJsonValue &jsonValue) {
-  _saveGeoCoordinate(coordinate, writeAltitude, jsonValue,
-                     false /* geoJsonFormat */);
+void JsonHelper::saveGeoCoordinate(const QGeoCoordinate&    coordinate,
+                                   bool                     writeAltitude,
+                                   QJsonValue&              jsonValue)
+{
+    _saveGeoCoordinate(coordinate, writeAltitude, jsonValue, false /* geoJsonFormat */);
 }
 
-bool JsonHelper::loadGeoJsonCoordinate(const QJsonValue &jsonValue,
-                                       bool altitudeRequired,
-                                       QGeoCoordinate &coordinate,
-                                       QString &errorString) {
-  return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate,
-                            errorString, true /* geoJsonFormat */);
+bool JsonHelper::loadGeoJsonCoordinate(const QJsonValue& jsonValue,
+                                       bool              altitudeRequired,
+                                       QGeoCoordinate&   coordinate,
+                                       QString&          errorString)
+{
+    return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate, errorString, true /* geoJsonFormat */);
 }
 
-void JsonHelper::saveGeoJsonCoordinate(const QGeoCoordinate &coordinate,
-                                       bool writeAltitude,
-                                       QJsonValue &jsonValue) {
-  _saveGeoCoordinate(coordinate, writeAltitude, jsonValue,
-                     true /* geoJsonFormat */);
+void JsonHelper::saveGeoJsonCoordinate(const QGeoCoordinate& coordinate,
+                                       bool                  writeAltitude,
+                                       QJsonValue&           jsonValue)
+{
+    _saveGeoCoordinate(coordinate, writeAltitude, jsonValue, true /* geoJsonFormat */);
 }
 
-bool JsonHelper::validateKeyTypes(const QJsonObject &jsonObject,
-                                  const QStringList &keys,
-                                  const QList<QJsonValue::Type> &types,
-                                  QString &errorString) {
-  for (int i = 0; i < types.count(); i++) {
-    QString valueKey = keys[i];
-    if (jsonObject.contains(valueKey)) {
-      const QJsonValue &jsonValue = jsonObject[valueKey];
-      if (jsonValue.type() == QJsonValue::Null &&
-          types[i] == QJsonValue::Double) {
-        // Null type signals a NaN on a double value
-        continue;
-      }
-      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;
-      }
+bool JsonHelper::validateKeyTypes(const QJsonObject& jsonObject, const QStringList& keys, const QList<QJsonValue::Type>& types, QString& errorString)
+{
+    for (int i=0; i<types.count(); i++) {
+        QString valueKey = keys[i];
+        if (jsonObject.contains(valueKey)) {
+            const QJsonValue& jsonValue = jsonObject[valueKey];
+            if (jsonValue.type() == QJsonValue::Null &&  types[i] == QJsonValue::Double) {
+                // Null type signals a NaN on a double value
+                continue;
+            }
+            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;
+            }
+        }
     }
-  }
 
-  return true;
+    return true;
 }
 
-bool JsonHelper::isJsonFile(const QByteArray &bytes, QJsonDocument &jsonDoc,
-                            QString &errorString) {
-  QJsonParseError parseError;
+bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QString& errorString)
+{
+    QJsonParseError parseError;
 
-  jsonDoc = QJsonDocument::fromJson(bytes, &parseError);
+    jsonDoc = QJsonDocument::fromJson(bytes, &parseError);
 
-  if (parseError.error == QJsonParseError::NoError) {
-    return true;
-  } else {
-    int startPos = qMax(0, parseError.offset - 100);
-    int length = qMin(bytes.count() - startPos, 200);
-    qDebug() << QStringLiteral("Json read error '%1'")
-                    .arg(bytes.mid(startPos, length).constData());
-    errorString = parseError.errorString();
-    return false;
-  }
+    if (parseError.error == QJsonParseError::NoError) {
+        return true;
+    } else {
+        int startPos = qMax(0, parseError.offset - 100);
+        int length = qMin(bytes.count() - startPos, 200);
+        qDebug() << QStringLiteral("Json read error '%1'").arg(bytes.mid(startPos, length).constData());
+        errorString = parseError.errorString();
+        return false;
+    }
 }
 
-bool JsonHelper::isJsonFile(const QString &fileName, QJsonDocument &jsonDoc,
-                            QString &errorString) {
-  QFile jsonFile(fileName);
-  if (!jsonFile.open(QFile::ReadOnly)) {
-    errorString = tr("File open failed: file:error %1 %2")
-                      .arg(jsonFile.fileName())
-                      .arg(jsonFile.errorString());
-    return false;
-  }
-  QByteArray jsonBytes = jsonFile.readAll();
-  jsonFile.close();
-
-  return isJsonFile(jsonBytes, jsonDoc, errorString);
-}
+bool JsonHelper::isJsonFile(const QString& fileName, QJsonDocument& jsonDoc, QString& errorString)
+{
+    QFile jsonFile(fileName);
+    if (!jsonFile.open(QFile::ReadOnly)) {
+        errorString = tr("File open failed: file:error %1 %2").arg(jsonFile.fileName()).arg(jsonFile.errorString());
+        return false;
+    }
+    QByteArray jsonBytes = jsonFile.readAll();
+    jsonFile.close();
 
-bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject &jsonObject,
-                                             const QString &expectedFileType,
-                                             int minSupportedVersion,
-                                             int maxSupportedVersion,
-                                             int &version,
-                                             QString &errorString) {
-  // Validate required keys
-  QList<JsonHelper::KeyValidateInfo> requiredKeys = {
-      {jsonFileTypeKey, QJsonValue::String, true},
-      {jsonVersionKey, QJsonValue::Double, true},
-  };
-  if (!JsonHelper::validateKeys(jsonObject, requiredKeys, errorString)) {
-    return false;
-  }
-
-  // Make sure file type is correct
-  QString fileTypeValue = jsonObject[jsonFileTypeKey].toString();
-  if (fileTypeValue != expectedFileType) {
-    errorString = QObject::tr("Incorrect file type key expected:%1 actual:%2")
-                      .arg(expectedFileType)
-                      .arg(fileTypeValue);
-    return false;
-  }
-
-  // Version check
-  version = jsonObject[jsonVersionKey].toInt();
-  if (version < minSupportedVersion) {
-    errorString =
-        QObject::tr("File version %1 is no longer supported").arg(version);
-    return false;
-  }
-  if (version > maxSupportedVersion) {
-    errorString =
-        QObject::tr(
-            "File version %1 is newer than current supported version %2")
-            .arg(version)
-            .arg(maxSupportedVersion);
-    return false;
-  }
-
-  return true;
+    return isJsonFile(jsonBytes, jsonDoc, errorString);
 }
 
-bool JsonHelper::validateExternalQGCJsonFile(const QJsonObject &jsonObject,
-                                             const QString &expectedFileType,
-                                             int minSupportedVersion,
-                                             int maxSupportedVersion,
-                                             int &version,
-                                             QString &errorString) {
-  // Validate required keys
-  QList<JsonHelper::KeyValidateInfo> requiredKeys = {
-      {jsonGroundStationKey, QJsonValue::String, true},
-  };
-  if (!JsonHelper::validateKeys(jsonObject, requiredKeys, errorString)) {
-    return false;
-  }
-
-  return validateInternalQGCJsonFile(jsonObject, expectedFileType,
-                                     minSupportedVersion, maxSupportedVersion,
-                                     version, errorString);
+bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject& jsonObject,
+                                             const QString&     expectedFileType,
+                                             int                minSupportedVersion,
+                                             int                maxSupportedVersion,
+                                             int&               version,
+                                             QString&           errorString)
+{
+    // Validate required keys
+    QList<JsonHelper::KeyValidateInfo> requiredKeys = {
+        { jsonFileTypeKey,       QJsonValue::String, true },
+        { jsonVersionKey,        QJsonValue::Double, true },
+    };
+    if (!JsonHelper::validateKeys(jsonObject, requiredKeys, errorString)) {
+        return false;
+    }
+
+    // Make sure file type is correct
+    QString fileTypeValue = jsonObject[jsonFileTypeKey].toString();
+    if (fileTypeValue != expectedFileType) {
+        errorString = QObject::tr("Incorrect file type key expected:%1 actual:%2").arg(expectedFileType).arg(fileTypeValue);
+        return false;
+    }
+
+    // Version check
+    version = jsonObject[jsonVersionKey].toInt();
+    if (version < minSupportedVersion) {
+        errorString = QObject::tr("File version %1 is no longer supported").arg(version);
+        return false;
+    }
+    if (version > maxSupportedVersion) {
+        errorString = QObject::tr("File version %1 is newer than current supported version %2").arg(version).arg(maxSupportedVersion);
+        return false;
+    }
+
+    return true;
 }
 
-QStringList JsonHelper::_addDefaultLocKeys(QJsonObject &jsonObject) {
-  QString translateKeys;
-  QString fileType = jsonObject[jsonFileTypeKey].toString();
-  if (!fileType.isEmpty()) {
-    if (fileType == MissionCommandList::qgcFileType) {
-      if (jsonObject.contains(_translateKeysKey)) {
-        translateKeys = jsonObject[_translateKeysKey].toString();
-      } else {
-        translateKeys = "label,enumStrings,friendlyName,description,category";
-        jsonObject[_translateKeysKey] = translateKeys;
-      }
-      if (!jsonObject.contains(_arrayIDKeysKey)) {
-        jsonObject[_arrayIDKeysKey] = "rawName,comment";
-      }
-    } else if (fileType == FactMetaData::qgcFileType) {
-      if (jsonObject.contains(_translateKeysKey)) {
-        translateKeys = jsonObject[_translateKeysKey].toString();
-      } else {
-        translateKeys = "shortDescription,longDescription,enumStrings";
-        jsonObject[_translateKeysKey] =
-            "shortDescription,longDescription,enumStrings";
-      }
-      if (!jsonObject.contains(_arrayIDKeysKey)) {
-        jsonObject[_arrayIDKeysKey] = "name";
-      }
-    }
-  }
-  return translateKeys.split(",");
+bool JsonHelper::validateExternalQGCJsonFile(const QJsonObject& jsonObject,
+                                             const QString&     expectedFileType,
+                                             int                minSupportedVersion,
+                                             int                maxSupportedVersion,
+                                             int&               version,
+                                             QString&           errorString)
+{
+    // Validate required keys
+    QList<JsonHelper::KeyValidateInfo> requiredKeys = {
+        { jsonGroundStationKey, QJsonValue::String, true },
+    };
+    if (!JsonHelper::validateKeys(jsonObject, requiredKeys, errorString)) {
+        return false;
+    }
+
+    return validateInternalQGCJsonFile(jsonObject, expectedFileType, minSupportedVersion, maxSupportedVersion, version, errorString);
 }
 
-QJsonObject JsonHelper::_translateObject(QJsonObject &jsonObject,
-                                         const QString &translateContext,
-                                         const QStringList &translateKeys) {
-  for (const QString &key : jsonObject.keys()) {
-    if (jsonObject[key].isString()) {
-      QString locString = jsonObject[key].toString();
-      if (translateKeys.contains(key)) {
-        QString disambiguation;
-        QString disambiguationPrefix("#loc.disambiguation#");
-
-        if (locString.startsWith(disambiguationPrefix)) {
-          locString = locString.right(locString.length() -
-                                      disambiguationPrefix.length());
-          int commentEndIndex = locString.indexOf("#");
-          if (commentEndIndex != -1) {
-            disambiguation = locString.left(commentEndIndex);
-            locString = locString.right(locString.length() -
-                                        disambiguation.length() - 1);
-          }
+QStringList JsonHelper::_addDefaultLocKeys(QJsonObject& jsonObject)
+{
+    QString translateKeys;
+    QString fileType = jsonObject[jsonFileTypeKey].toString();
+    if (!fileType.isEmpty()) {
+        if (fileType == MissionCommandList::qgcFileType) {
+            if (jsonObject.contains(_translateKeysKey)) {
+                translateKeys = jsonObject[_translateKeysKey].toString();
+            } else {
+                translateKeys = "label,enumStrings,friendlyName,description,category";
+                jsonObject[_translateKeysKey] = translateKeys;
+            }
+            if (!jsonObject.contains(_arrayIDKeysKey)) {
+                jsonObject[_arrayIDKeysKey] = "rawName,comment";
+            }
+        } else if (fileType == FactMetaData::qgcFileType) {
+            if (jsonObject.contains(_translateKeysKey)) {
+                translateKeys = jsonObject[_translateKeysKey].toString();
+            } else {
+                translateKeys = "shortDescription,longDescription,enumStrings";
+                jsonObject[_translateKeysKey] = "shortDescription,longDescription,enumStrings";
+            }
+            if (!jsonObject.contains(_arrayIDKeysKey)) {
+                jsonObject[_arrayIDKeysKey] = "name";
+            }
         }
+    }
+    return translateKeys.split(",");
+}
 
-        QString xlatString = qgcApp()->qgcJSONTranslator().translate(
-            translateContext.toUtf8().constData(),
-            locString.toUtf8().constData(),
-            disambiguation.toUtf8().constData());
-        if (!xlatString.isNull()) {
-          jsonObject[key] = xlatString;
+QJsonObject JsonHelper::_translateObject(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys)
+{
+    for (const QString& key: jsonObject.keys()) {
+        if (jsonObject[key].isString()) {
+            QString locString = jsonObject[key].toString();
+            if (translateKeys.contains(key)) {
+                QString disambiguation;
+                QString disambiguationPrefix("#loc.disambiguation#");
+
+                if (locString.startsWith(disambiguationPrefix)) {
+                    locString = locString.right(locString.length() - disambiguationPrefix.length());
+                    int commentEndIndex = locString.indexOf("#");
+                    if (commentEndIndex != -1) {
+                        disambiguation = locString.left(commentEndIndex);
+                        locString = locString.right(locString.length() - disambiguation.length() - 1);
+                    }
+                }
+
+                QString xlatString = qgcApp()->qgcJSONTranslator().translate(translateContext.toUtf8().constData(), locString.toUtf8().constData(), disambiguation.toUtf8().constData());
+                if (!xlatString.isNull()) {
+                    jsonObject[key] = xlatString;
+                }
+            }
+        } else if (jsonObject[key].isArray()) {
+            QJsonArray childJsonArray = jsonObject[key].toArray();
+            jsonObject[key] = _translateArray(childJsonArray, translateContext, translateKeys);
+        } else if (jsonObject[key].isObject()) {
+            QJsonObject childJsonObject = jsonObject[key].toObject();
+            jsonObject[key] = _translateObject(childJsonObject, translateContext, translateKeys);
         }
-      }
-    } else if (jsonObject[key].isArray()) {
-      QJsonObject childJsonArray = jsonObject[key].toArray();
-      jsonObject[key] =
-          _translateArray(childJsonArray, translateContext, translateKeys);
-    } else if (jsonObject[key].isObject()) {
-      QJsonObject childJsonObject = jsonObject[key].toObject();
-      jsonObject[key] =
-          _translateObject(childJsonObject, translateContext, translateKeys);
-    }
-  }
-
-  return jsonObject;
+    }
+
+    return jsonObject;
 }
 
-QJsonObject JsonHelper::_translateArray(QJsonObject &jsonArray,
-                                        const QString &translateContext,
-                                        const QStringList &translateKeys) {
-  for (int i = 0; i < jsonArray.count(); i++) {
-    QJsonObject childJsonObject = jsonArray[i].toObject();
-    jsonArray[i] =
-        _translateObject(childJsonObject, translateContext, translateKeys);
-  }
+QJsonArray JsonHelper::_translateArray(QJsonArray& jsonArray, const QString& translateContext, const QStringList& translateKeys)
+{
+    for (int i=0; i<jsonArray.count(); i++) {
+        QJsonObject childJsonObject = jsonArray[i].toObject();
+        jsonArray[i] = _translateObject(childJsonObject, translateContext, translateKeys);
+    }
 
-  return jsonArray;
+    return jsonArray;
 }
 
-QJsonObject JsonHelper::_translateRoot(QJsonObject &jsonObject,
-                                       const QString &translateContext,
-                                       const QStringList &translateKeys) {
-  return _translateObject(jsonObject, translateContext, translateKeys);
+QJsonObject JsonHelper::_translateRoot(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys)
+{
+    return _translateObject(jsonObject, translateContext, translateKeys);
 }
 
-QJsonObject JsonHelper::openInternalQGCJsonFile(const QString &jsonFilename,
-                                                const QString &expectedFileType,
-                                                int minSupportedVersion,
-                                                int maxSupportedVersion,
-                                                int &version,
-                                                QString &errorString) {
-  QFile jsonFile(jsonFilename);
-  if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
-    errorString = tr("Unable to open file: '%1', error: %2")
-                      .arg(jsonFilename)
-                      .arg(jsonFile.errorString());
-    return QJsonObject();
-  }
-
-  QByteArray bytes = jsonFile.readAll();
-  jsonFile.close();
-  QJsonParseError jsonParseError;
-  QJsonDocument doc = QJsonDocument::fromJson(bytes, &jsonParseError);
-  if (jsonParseError.error != QJsonParseError::NoError) {
-    errorString = tr("Unable to parse json file: %1 error: %2 offset: %3")
-                      .arg(jsonFilename)
-                      .arg(jsonParseError.errorString())
-                      .arg(jsonParseError.offset);
-    return QJsonObject();
-  }
-
-  if (!doc.isObject()) {
-    errorString = tr("Root of json file is not object: %1").arg(jsonFilename);
-    return QJsonObject();
-  }
-
-  QJsonObject jsonObject = doc.object();
-  bool success = validateInternalQGCJsonFile(
-      jsonObject, expectedFileType, minSupportedVersion, maxSupportedVersion,
-      version, errorString);
-  if (!success) {
-    errorString = tr("Json file: '%1'. %2").arg(jsonFilename).arg(errorString);
-    return QJsonObject();
-  }
-
-  QStringList translateKeys = _addDefaultLocKeys(jsonObject);
-  QString context = QFileInfo(jsonFile).fileName();
-  return _translateRoot(jsonObject, context, translateKeys);
+QJsonObject JsonHelper::openInternalQGCJsonFile(const QString&  jsonFilename,
+                                                const QString&  expectedFileType,
+                                                int             minSupportedVersion,
+                                                int             maxSupportedVersion,
+                                                int             &version,
+                                                QString&        errorString)
+{
+    QFile jsonFile(jsonFilename);
+    if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        errorString = tr("Unable to open file: '%1', error: %2").arg(jsonFilename).arg(jsonFile.errorString());
+        return QJsonObject();
+    }
+
+    QByteArray bytes = jsonFile.readAll();
+    jsonFile.close();
+    QJsonParseError jsonParseError;
+    QJsonDocument doc = QJsonDocument::fromJson(bytes, &jsonParseError);
+    if (jsonParseError.error != QJsonParseError::NoError) {
+        errorString = tr("Unable to parse json file: %1 error: %2 offset: %3").arg(jsonFilename).arg(jsonParseError.errorString()).arg(jsonParseError.offset);
+        return QJsonObject();
+    }
+
+    if (!doc.isObject()) {
+        errorString = tr("Root of json file is not object: %1").arg(jsonFilename);
+        return QJsonObject();
+    }
+
+    QJsonObject jsonObject = doc.object();
+    bool success = validateInternalQGCJsonFile(jsonObject, expectedFileType, minSupportedVersion, maxSupportedVersion, version, errorString);
+    if (!success) {
+        errorString = tr("Json file: '%1'. %2").arg(jsonFilename).arg(errorString);
+        return QJsonObject();
+    }
+
+    QStringList translateKeys = _addDefaultLocKeys(jsonObject);
+    QString context = QFileInfo(jsonFile).fileName();
+    return _translateRoot(jsonObject, context, translateKeys);
 }
 
-void JsonHelper::saveQGCJsonFileHeader(QJsonObject &jsonObject,
-                                       const QString &fileType, int version) {
-  jsonObject[jsonGroundStationKey] = jsonGroundStationValue;
-  jsonObject[jsonFileTypeKey] = fileType;
-  jsonObject[jsonVersionKey] = version;
+void JsonHelper::saveQGCJsonFileHeader(QJsonObject&     jsonObject,
+                                       const QString&   fileType,
+                                       int              version)
+{
+    jsonObject[jsonGroundStationKey] = jsonGroundStationValue;
+    jsonObject[jsonFileTypeKey] = fileType;
+    jsonObject[jsonVersionKey] = version;
 }
 
-bool JsonHelper::loadGeoCoordinateArray(const QJsonValue &jsonValue,
-                                        bool altitudeRequired,
-                                        QVariantList &rgVarPoints,
-                                        QString &errorString) {
-  if (!jsonValue.isArray()) {
-    errorString = QObject::tr("value for coordinate array is not array");
-    return false;
-  }
-  QJsonObject rgJsonPoints = jsonValue.toArray();
+bool JsonHelper::loadGeoCoordinateArray(const QJsonValue&   jsonValue,
+                                        bool                altitudeRequired,
+                                        QVariantList&       rgVarPoints,
+                                        QString&            errorString)
+{
+    if (!jsonValue.isArray()) {
+        errorString = QObject::tr("value for coordinate array is not array");
+        return false;
+    }
+    QJsonArray rgJsonPoints = jsonValue.toArray();
 
-  rgVarPoints.clear();
-  for (int i = 0; i < rgJsonPoints.count(); i++) {
-    QGeoCoordinate coordinate;
+    rgVarPoints.clear();
+    for (int i=0; i<rgJsonPoints.count(); i++) {
+        QGeoCoordinate coordinate;
 
-    if (!JsonHelper::loadGeoCoordinate(rgJsonPoints[i], altitudeRequired,
-                                       coordinate, errorString)) {
-      return false;
+        if (!JsonHelper::loadGeoCoordinate(rgJsonPoints[i], altitudeRequired, coordinate, errorString)) {
+            return false;
+        }
+        rgVarPoints.append(QVariant::fromValue(coordinate));
     }
-    rgVarPoints.append(QVariant::fromValue(coordinate));
-  }
 
-  return true;
+    return true;
 }
 
-bool JsonHelper::loadGeoCoordinateArray(const QJsonValue &jsonValue,
-                                        bool altitudeRequired,
-                                        QList<QGeoCoordinate> &rgPoints,
-                                        QString &errorString) {
-  QVariantList rgVarPoints;
+bool JsonHelper::loadGeoCoordinateArray(const QJsonValue&       jsonValue,
+                                        bool                    altitudeRequired,
+                                        QList<QGeoCoordinate>&  rgPoints,
+                                        QString&                errorString)
+{
+    QVariantList rgVarPoints;
 
-  if (!loadGeoCoordinateArray(jsonValue, altitudeRequired, rgVarPoints,
-                              errorString)) {
-    return false;
-  }
+    if (!loadGeoCoordinateArray(jsonValue, altitudeRequired, rgVarPoints, errorString)) {
+        return false;
+    }
 
-  rgPoints.clear();
-  for (int i = 0; i < rgVarPoints.count(); i++) {
-    rgPoints.append(rgVarPoints[i].value<QGeoCoordinate>());
-  }
+    rgPoints.clear();
+    for (int i=0; i<rgVarPoints.count(); i++) {
+        rgPoints.append(rgVarPoints[i].value<QGeoCoordinate>());
+    }
 
-  return true;
+    return true;
 }
 
-void JsonHelper::saveGeoCoordinateArray(const QVariantList &rgVarPoints,
-                                        bool writeAltitude,
-                                        QJsonValue &jsonValue) {
-  QJsonObject rgJsonPoints;
+void JsonHelper::saveGeoCoordinateArray(const QVariantList& rgVarPoints,
+                                        bool                writeAltitude,
+                                        QJsonValue&         jsonValue)
+{
+    QJsonArray rgJsonPoints;
 
-  // Add all points to the array
-  for (int i = 0; i < rgVarPoints.count(); i++) {
-    QJsonValue jsonPoint;
+    // Add all points to the array
+    for (int i=0; i<rgVarPoints.count(); i++) {
+        QJsonValue jsonPoint;
 
-    JsonHelper::saveGeoCoordinate(rgVarPoints[i].value<QGeoCoordinate>(),
-                                  writeAltitude, jsonPoint);
-    rgJsonPoints.append(jsonPoint);
-  }
+        JsonHelper::saveGeoCoordinate(rgVarPoints[i].value<QGeoCoordinate>(), writeAltitude, jsonPoint);
+        rgJsonPoints.append(jsonPoint);
+    }
 
-  jsonValue = rgJsonPoints;
+    jsonValue = rgJsonPoints;
 }
 
-void JsonHelper::saveGeoCoordinateArray(const QList<QGeoCoordinate> &rgPoints,
-                                        bool writeAltitude,
-                                        QJsonValue &jsonValue) {
-  QVariantList rgVarPoints;
+void JsonHelper::saveGeoCoordinateArray(const QList<QGeoCoordinate>&    rgPoints,
+                                        bool                            writeAltitude,
+                                        QJsonValue&                     jsonValue)
+{
+    QVariantList rgVarPoints;
 
-  for (int i = 0; i < rgPoints.count(); i++) {
-    rgVarPoints.append(QVariant::fromValue(rgPoints[i]));
-  }
-  return saveGeoCoordinateArray(rgVarPoints, writeAltitude, jsonValue);
+    for (int i=0; i<rgPoints.count(); i++) {
+        rgVarPoints.append(QVariant::fromValue(rgPoints[i]));
+    }
+    return saveGeoCoordinateArray(rgVarPoints, writeAltitude, jsonValue);
 }
 
-bool JsonHelper::validateKeys(const QJsonObject &jsonObject,
-                              const QList<JsonHelper::KeyValidateInfo> &keyInfo,
-                              QString &errorString) {
-  QStringList keyList;
-  QList<QJsonValue::Type> typeList;
-
-  for (int i = 0; i < keyInfo.count(); i++) {
-    if (keyInfo[i].required) {
-      keyList.append(keyInfo[i].key);
-    }
-  }
-  if (!validateRequiredKeys(jsonObject, keyList, errorString)) {
-    return false;
-  }
-
-  keyList.clear();
-  for (int i = 0; i < keyInfo.count(); i++) {
-    keyList.append(keyInfo[i].key);
-    typeList.append(keyInfo[i].type);
-  }
-  return validateKeyTypes(jsonObject, keyList, typeList, errorString);
+bool JsonHelper::validateKeys(const QJsonObject& jsonObject, const QList<JsonHelper::KeyValidateInfo>& keyInfo, QString& errorString)
+{
+    QStringList             keyList;
+    QList<QJsonValue::Type> typeList;
+
+    for (int i=0; i<keyInfo.count(); i++) {
+        if (keyInfo[i].required) {
+            keyList.append(keyInfo[i].key);
+        }
+    }
+    if (!validateRequiredKeys(jsonObject, keyList, errorString)) {
+        return false;
+    }
+
+    keyList.clear();
+    for (int i=0; i<keyInfo.count(); i++) {
+        keyList.append(keyInfo[i].key);
+        typeList.append(keyInfo[i].type);
+    }
+    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);
+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);
 }
 
-bool JsonHelper::loadPolygon(const QJsonObject &polygonArray,
-                             QmlObjectListModel &list, QObject *parent,
-                             QString &errorString) {
-  for (int i = 0; i < polygonArray.count(); i++) {
-    const QJsonValue &pointValue = polygonArray[i];
+bool JsonHelper::loadPolygon(const QJsonArray& polygonArray, QmlObjectListModel& list, QObject* parent, QString& errorString)
+{
+    for (int i=0; i<polygonArray.count(); i++) {
+        const QJsonValue& pointValue = polygonArray[i];
 
-    QGeoCoordinate pointCoord;
-    if (!JsonHelper::loadGeoCoordinate(pointValue, false /* altitudeRequired */,
-                                       pointCoord, errorString, true)) {
-      list.clearAndDeleteContents();
-      return false;
+        QGeoCoordinate pointCoord;
+        if (!JsonHelper::loadGeoCoordinate(pointValue, false /* altitudeRequired */, pointCoord, errorString, true)) {
+            list.clearAndDeleteContents();
+            return false;
+        }
+        list.append(new QGCQGeoCoordinate(pointCoord, parent));
     }
-    list.append(new QGCQGeoCoordinate(pointCoord, parent));
-  }
 
-  return true;
+    return true;
 }
 
-void JsonHelper::savePolygon(QmlObjectListModel &list,
-                             QJsonObject &polygonArray) {
-  for (int i = 0; i < list.count(); i++) {
-    QGeoCoordinate vertex = list.value<QGCQGeoCoordinate *>(i)->coordinate();
+void JsonHelper::savePolygon(QmlObjectListModel& list, QJsonArray& polygonArray)
+{
+    for (int i=0; i<list.count(); i++) {
+        QGeoCoordinate vertex = list.value<QGCQGeoCoordinate*>(i)->coordinate();
 
-    QJsonValue jsonValue;
-    JsonHelper::saveGeoCoordinate(vertex, false /* writeAltitude */, jsonValue);
-    polygonArray.append(jsonValue);
-  }
+        QJsonValue jsonValue;
+        JsonHelper::saveGeoCoordinate(vertex, false /* writeAltitude */, jsonValue);
+        polygonArray.append(jsonValue);
+    }
 }
 
-double JsonHelper::possibleNaNJsonValue(const QJsonValue &value) {
-  if (value.type() == QJsonValue::Null) {
-    return std::numeric_limits<double>::quiet_NaN();
-  } else {
-    return value.toDouble();
-  }
+double JsonHelper::possibleNaNJsonValue(const  QJsonValue& value)
+{
+    if (value.type() == QJsonValue::Null) {
+        return std::numeric_limits<double>::quiet_NaN();
+    } else {
+        return value.toDouble();
+    }
 }
diff --git a/src/JsonHelper.h b/src/JsonHelper.h
index f953ebe68d9918f0350984778a94bcc16cd434a3..74a9634ea9e5046dfcb8e926603d5013080451c5 100644
--- a/src/JsonHelper.h
+++ b/src/JsonHelper.h
@@ -9,10 +9,10 @@
 
 #pragma once
 
-#include <QCoreApplication>
-#include <QGeoCoordinate>
 #include <QJsonObject>
 #include <QVariantList>
+#include <QGeoCoordinate>
+#include <QCoreApplication>
 
 /// @file
 /// @author Don Gagne <don@thegagnes.com>
@@ -21,193 +21,164 @@ class QmlObjectListModel;
 
 /// @brief Json manipulation helper class.
 /// Primarily used for parsing and processing Fact metadata.
-class JsonHelper {
-  Q_DECLARE_TR_FUNCTIONS(JsonHelper)
+class JsonHelper
+{
+    Q_DECLARE_TR_FUNCTIONS(JsonHelper)
 
 public:
-  /// Determines is the specified file is a json file
-  /// @return true: file is json, false: file is not json
-  static bool isJsonFile(const QString &fileName, ///< filename
-                         QJsonDocument &jsonDoc,  ///< returned json document
-                         QString &errorString);   ///< error on parse failure
-
-  /// Determines is the specified data is a json file
-  /// @return true: file is json, false: file is not json
-  static bool isJsonFile(const QByteArray &bytes, ///< json bytes
-                         QJsonDocument &jsonDoc,  ///< returned json document
-                         QString &errorString);   ///< error on parse failure
-
-  /// Saves the standard file header the json object
-  static void
-  saveQGCJsonFileHeader(QJsonObject &jsonObject, ///< root json object
-                        const QString &fileType, ///< file type for file
-                        int version);            ///< version number for file
-
-  /// Validates the standard parts of an external QGC json file (Plan 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, errorString set
-  static bool validateExternalQGCJsonFile(
-      const QJsonObject &jsonObject,   ///< json object to validate
-      const QString &expectedFileType, ///< correct file type for file
-      int minSupportedVersion,         ///< minimum supported version
-      int maxSupportedVersion,         ///< maximum supported major version
-      int &version,                    ///< returned file version
-      QString &errorString); ///< returned error string if validation fails
-
-  /// Validates the standard parts of a internal QGC json file (FactMetaData,
-  /// ...):
-  ///     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, errorString set
-  static bool validateInternalQGCJsonFile(
-      const QJsonObject &jsonObject,   ///< json object to validate
-      const QString &expectedFileType, ///< correct file type for file
-      int minSupportedVersion,         ///< minimum supported version
-      int maxSupportedVersion,         ///< maximum supported major version
-      int &version,                    ///< returned file version
-      QString &errorString); ///< returned error string if validation fails
-
-  // Opens, validates and translates an internal QGC json file.
-  // @return Json root object for file. Empty QJsonObject if error.
-  static QJsonObject openInternalQGCJsonFile(
-      const QString &jsonFilename,     ///< Json file to open
-      const QString &expectedFileType, ///< correct file type for file
-      int minSupportedVersion,         ///< minimum supported version
-      int maxSupportedVersion,         ///< maximum supported major version
-      int &version,                    ///< returned file version
-      QString &errorString); ///< returned error string if validation fails
-
-  /// Validates that the specified keys are in the object
-  /// @return false: validation failed, errorString set
-  static bool validateRequiredKeys(
-      const QJsonObject &jsonObject, ///< json object to validate
-      const QStringList &keys,       ///< keys which are required to be present
-      QString &errorString); ///< returned error string if validation fails
-
-  /// Validates the types of specified keys are in the object
-  /// @return false: validation failed, errorString set
-  static bool validateKeyTypes(
-      const QJsonObject &jsonObject, ///< json object to validate
-      const QStringList &keys,       ///< keys to validate
-      const QList<QJsonValue::Type>
-          &types, ///< required type for each key, QJsonValue::Null specifies
-                  ///< double with possible NaN
-      QString &errorString); ///< returned error string if validation fails
-
-  typedef struct {
-    const char *key;       ///< json key name
-    QJsonValue::Type type; ///< required type for key, QJsonValue::Null
-                           ///< specifies double with possible NaN
-    bool required;         ///< true: key must be present
-  } KeyValidateInfo;
-
-  static bool validateKeys(const QJsonObject &jsonObject,
-                           const QList<KeyValidateInfo> &keyInfo,
-                           QString &errorString);
-
-  /// Loads a QGeoCoordinate
-  ///     Stored as array [ lat, lon, alt ]
-  /// @return false: validation failed
-  static bool loadGeoCoordinate(
-      const QJsonValue &jsonValue, ///< json value to load from
-      bool altitudeRequired,       ///< true: altitude must be specified
-      QGeoCoordinate &coordinate,  ///< returned QGeoCordinate
-      QString &errorString,        ///< returned error string if load failure
-      bool geoJsonFormat =
-          false); ///< if true, use [lon, lat], [lat, lon] otherwise
-
-  /// Saves a QGeoCoordinate
-  ///     Stored as array [ lat, lon, alt ]
-  static void saveGeoCoordinate(
-      const QGeoCoordinate &coordinate, ///< QGeoCoordinate to save
-      bool writeAltitude,               ///< true: write altitude to json
-      QJsonValue &jsonValue);           ///< json value to save to
-
-  /// Loads a QGeoCoordinate
-  ///     Stored as array [ lon, lat, alt ]
-  /// @return false: validation failed
-  static bool loadGeoJsonCoordinate(
-      const QJsonValue &jsonValue, ///< json value to load from
-      bool altitudeRequired,       ///< true: altitude must be specified
-      QGeoCoordinate &coordinate,  ///< returned QGeoCordinate
-      QString &errorString);       ///< returned error string if load failure
-
-  /// Saves a QGeoCoordinate
-  ///     Stored as array [ lon, lat, alt ]
-  static void saveGeoJsonCoordinate(
-      const QGeoCoordinate &coordinate, ///< QGeoCoordinate to save
-      bool writeAltitude,               ///< true: write altitude to json
-      QJsonValue &jsonValue);           ///< json value to save to
-
-  /// Loads a polygon from an array
-  static bool loadPolygon(
-      const QJsonObject &polygonArray, ///< Array of coordinates
-      QmlObjectListModel &list,        ///< Empty list to add vertices to
-      QObject *parent,       ///< parent for newly allocated QGCQGeoCoordinates
-      QString &errorString); ///< returned error string if load failure
-
-  /// Loads a list of QGeoCoordinates from a json array
-  /// @return false: validation failed
-  static bool loadGeoCoordinateArray(
-      const QJsonValue &jsonValue, ///< json value which contains points
-      bool altitudeRequired,       ///< true: altitude field must be specified
-      QVariantList &rgVarPoints,   ///< returned points
-      QString &errorString);       ///< returned error string if load failure
-  static bool loadGeoCoordinateArray(
-      const QJsonValue &jsonValue, ///< json value which contains points
-      bool altitudeRequired,       ///< true: altitude field must be specified
-      QList<QGeoCoordinate> &rgPoints, ///< returned points
-      QString &errorString); ///< returned error string if load failure
-
-  /// Saves a list of QGeoCoordinates to a json array
-  static void
-  saveGeoCoordinateArray(const QVariantList &rgVarPoints, ///< points to save
-                         bool writeAltitude,     ///< true: write altitide value
-                         QJsonValue &jsonValue); ///< json value to save to
-  static void saveGeoCoordinateArray(
-      const QList<QGeoCoordinate> &rgPoints, ///< points to save
-      bool writeAltitude,                    ///< true: write altitide value
-      QJsonValue &jsonValue);                ///< json value to save to
-
-  /// Saves a polygon to a json array
-  static void
-  savePolygon(QmlObjectListModel &list,   ///< List which contains vertices
-              QJsonObject &polygonArray); ///< Array to save into
-
-  /// Returns NaN if the value is null, or if not, the double value
-  static double possibleNaNJsonValue(const QJsonValue &value);
-
-  static const char *jsonVersionKey;
-  static const char *jsonGroundStationKey;
-  static const char *jsonGroundStationValue;
-  static const char *jsonFileTypeKey;
+    /// Determines is the specified file is a json file
+    /// @return true: file is json, false: file is not json
+    static bool isJsonFile(const QString&       fileName,       ///< filename
+                           QJsonDocument&       jsonDoc,        ///< returned json document
+                           QString&             errorString);   ///< error on parse failure
+
+    /// Determines is the specified data is a json file
+    /// @return true: file is json, false: file is not json
+    static bool isJsonFile(const QByteArray&    bytes,          ///< json bytes
+                           QJsonDocument&       jsonDoc,        ///< returned json document
+                           QString&             errorString);   ///< error on parse failure
+
+    /// Saves the standard file header the json object
+    static void saveQGCJsonFileHeader(QJsonObject&      jsonObject, ///< root json object
+                                      const QString&    fileType,   ///< file type for file
+                                      int               version);   ///< version number for file
+
+    /// Validates the standard parts of an external QGC json file (Plan 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, errorString set
+    static bool validateExternalQGCJsonFile(const QJsonObject&  jsonObject,             ///< json object to validate
+                                            const QString&      expectedFileType,       ///< correct file type for file
+                                            int                 minSupportedVersion,    ///< minimum supported version
+                                            int                 maxSupportedVersion,    ///< maximum supported major version
+                                            int                 &version,               ///< returned file version
+                                            QString&            errorString);           ///< returned error string if validation fails
+
+    /// Validates the standard parts of a internal QGC json file (FactMetaData, ...):
+    ///     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, errorString set
+    static bool validateInternalQGCJsonFile(const QJsonObject&  jsonObject,             ///< json object to validate
+                                            const QString&      expectedFileType,       ///< correct file type for file
+                                            int                 minSupportedVersion,    ///< minimum supported version
+                                            int                 maxSupportedVersion,    ///< maximum supported major version
+                                            int                 &version,               ///< returned file version
+                                            QString&            errorString);           ///< returned error string if validation fails
+
+    // Opens, validates and translates an internal QGC json file.
+    // @return Json root object for file. Empty QJsonObject if error.
+    static QJsonObject openInternalQGCJsonFile(const QString& jsonFilename,             ///< Json file to open
+                                               const QString&      expectedFileType,    ///< correct file type for file
+                                               int                 minSupportedVersion, ///< minimum supported version
+                                               int                 maxSupportedVersion, ///< maximum supported major version
+                                               int                 &version,            ///< returned file version
+                                               QString&            errorString);        ///< returned error string if validation fails
+
+    /// Validates that the specified keys are in the object
+    /// @return false: validation failed, errorString set
+    static bool validateRequiredKeys(const QJsonObject& jsonObject, ///< json object to validate
+                                     const QStringList& keys,       ///< keys which are required to be present
+                                     QString& errorString);         ///< returned error string if validation fails
+
+    /// Validates the types of specified keys are in the object
+    /// @return false: validation failed, errorString set
+    static bool validateKeyTypes(const QJsonObject& jsonObject,         ///< json object to validate
+                                 const QStringList& keys,               ///< keys to validate
+                                 const QList<QJsonValue::Type>& types,  ///< required type for each key, QJsonValue::Null specifies double with possible NaN
+                                 QString& errorString);                 ///< returned error string if validation fails
+
+    typedef struct {
+        const char*         key;        ///< json key name
+        QJsonValue::Type    type;       ///< required type for key, QJsonValue::Null specifies double with possible NaN
+        bool                required;   ///< true: key must be present
+    } KeyValidateInfo;
+
+    static bool validateKeys(const QJsonObject& jsonObject, const QList<KeyValidateInfo>& keyInfo, QString& errorString);
+
+    /// Loads a QGeoCoordinate
+    ///     Stored as array [ lat, lon, alt ]
+    /// @return false: validation failed
+    static bool loadGeoCoordinate(const QJsonValue& jsonValue,              ///< json value to load from
+                                  bool              altitudeRequired,       ///< true: altitude must be specified
+                                  QGeoCoordinate&   coordinate,             ///< returned QGeoCordinate
+                                  QString&          errorString,            ///< returned error string if load failure
+                                  bool              geoJsonFormat = false); ///< if true, use [lon, lat], [lat, lon] otherwise
+
+    /// Saves a QGeoCoordinate
+    ///     Stored as array [ lat, lon, alt ]
+    static void saveGeoCoordinate(const QGeoCoordinate& coordinate,     ///< QGeoCoordinate to save
+                                  bool                  writeAltitude,  ///< true: write altitude to json
+                                  QJsonValue&           jsonValue);     ///< json value to save to
+
+    /// Loads a QGeoCoordinate
+    ///     Stored as array [ lon, lat, alt ]
+    /// @return false: validation failed
+    static bool loadGeoJsonCoordinate(const QJsonValue& jsonValue,          ///< json value to load from
+                                      bool              altitudeRequired,   ///< true: altitude must be specified
+                                      QGeoCoordinate&   coordinate,         ///< returned QGeoCordinate
+                                      QString&          errorString);       ///< returned error string if load failure
+
+    /// Saves a QGeoCoordinate
+    ///     Stored as array [ lon, lat, alt ]
+    static void saveGeoJsonCoordinate(const QGeoCoordinate& coordinate,     ///< QGeoCoordinate to save
+                                      bool                  writeAltitude,  ///< true: write altitude to json
+                                      QJsonValue&           jsonValue);     ///< json value to save to
+
+    /// Loads a polygon from an array
+    static bool loadPolygon(const QJsonArray&   polygonArray,   ///< Array of coordinates
+                            QmlObjectListModel& list,           ///< Empty list to add vertices to
+                            QObject*            parent,         ///< parent for newly allocated QGCQGeoCoordinates
+                            QString&            errorString);   ///< returned error string if load failure
+
+    /// Loads a list of QGeoCoordinates from a json array
+    /// @return false: validation failed
+    static bool loadGeoCoordinateArray(const QJsonValue&    jsonValue,              ///< json value which contains points
+                                       bool                 altitudeRequired,       ///< true: altitude field must be specified
+                                       QVariantList&        rgVarPoints,            ///< returned points
+                                       QString&             errorString);           ///< returned error string if load failure
+    static bool loadGeoCoordinateArray(const QJsonValue&        jsonValue,          ///< json value which contains points
+                                       bool                     altitudeRequired,   ///< true: altitude field must be specified
+                                       QList<QGeoCoordinate>&   rgPoints,           ///< returned points
+                                       QString&                 errorString);       ///< returned error string if load failure
+
+    /// Saves a list of QGeoCoordinates to a json array
+    static void saveGeoCoordinateArray(const QVariantList&  rgVarPoints,            ///< points to save
+                                       bool                 writeAltitude,          ///< true: write altitide value
+                                       QJsonValue&          jsonValue);             ///< json value to save to
+    static void saveGeoCoordinateArray(const QList<QGeoCoordinate>& rgPoints,       ///< points to save
+                                       bool                         writeAltitude,  ///< true: write altitide value
+                                       QJsonValue&                  jsonValue);     ///< json value to save to
+
+    /// Saves a polygon to a json array
+    static void savePolygon(QmlObjectListModel& list,           ///< List which contains vertices
+                            QJsonArray&         polygonArray);  ///< Array to save into
+
+    /// Returns NaN if the value is null, or if not, the double value
+    static double possibleNaNJsonValue(const QJsonValue& value);
+
+    static const char* jsonVersionKey;
+    static const char* jsonGroundStationKey;
+    static const char* jsonGroundStationValue;
+    static const char* jsonFileTypeKey;
 
 private:
-  static QString _jsonValueTypeToString(QJsonValue::Type type);
-  static bool _loadGeoCoordinate(const QJsonValue &jsonValue,
-                                 bool altitudeRequired,
-                                 QGeoCoordinate &coordinate,
-                                 QString &errorString, bool geoJsonFormat);
-  static void _saveGeoCoordinate(const QGeoCoordinate &coordinate,
-                                 bool writeAltitude, QJsonValue &jsonValue,
-                                 bool geoJsonFormat);
-  static QStringList _addDefaultLocKeys(QJsonObject &jsonObject);
-  static QJsonObject _translateRoot(QJsonObject &jsonObject,
-                                    const QString &translateContext,
-                                    const QStringList &translateKeys);
-  static QJsonObject _translateObject(QJsonObject &jsonObject,
-                                      const QString &translateContext,
-                                      const QStringList &translateKeys);
-  static QJsonObject _translateArray(QJsonObject &jsonArray,
-                                     const QString &translateContext,
-                                     const QStringList &translateKeys);
-
-  static const char *_translateKeysKey;
-  static const char *_arrayIDKeysKey;
+    static QString _jsonValueTypeToString(QJsonValue::Type type);
+    static bool _loadGeoCoordinate(const QJsonValue&    jsonValue,
+                                   bool                 altitudeRequired,
+                                   QGeoCoordinate&      coordinate,
+                                   QString&             errorString,
+                                   bool                 geoJsonFormat);
+    static void _saveGeoCoordinate(const QGeoCoordinate&    coordinate,
+                                   bool                     writeAltitude,
+                                   QJsonValue&              jsonValue,
+                                   bool                     geoJsonFormat);
+    static QStringList _addDefaultLocKeys(QJsonObject& jsonObject);
+    static QJsonObject _translateRoot(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys);
+    static QJsonObject _translateObject(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys);
+    static QJsonArray _translateArray(QJsonArray& jsonArray, const QString& translateContext, const QStringList& translateKeys);
+
+    static const char*  _translateKeysKey;
+    static const char*  _arrayIDKeysKey;
 };
diff --git a/src/MissionManager/CorridorScanComplexItem.cc b/src/MissionManager/CorridorScanComplexItem.cc
index 704922bbae1be8a90b9d74d82eab2bffae515cae..73836271ebe33788ca2cff3e898e263f74138e58 100644
--- a/src/MissionManager/CorridorScanComplexItem.cc
+++ b/src/MissionManager/CorridorScanComplexItem.cc
@@ -61,7 +61,7 @@ CorridorScanComplexItem::CorridorScanComplexItem(PlanMasterController* masterCon
     setDirty(false);
 }
 
-void CorridorScanComplexItem::save(QJsonObject&  planItems)
+void CorridorScanComplexItem::save(QJsonArray&  planItems)
 {
     QJsonObject saveObject;
 
diff --git a/src/MissionManager/CorridorScanComplexItem.h b/src/MissionManager/CorridorScanComplexItem.h
index f4537251cc26575b1dff9a7c886924092abcfbba..6eefc413e65fb685aa0ec20103f93ec6520a5360 100644
--- a/src/MissionManager/CorridorScanComplexItem.h
+++ b/src/MissionManager/CorridorScanComplexItem.h
@@ -37,7 +37,7 @@ public:
 
     // Overrides from TransectStyleComplexItem
     QString patternName         (void) const final { return name; }
-    void    save                (QJsonObject&  planItems) final;
+    void    save                (QJsonArray&  planItems) final;
     bool    specifiesCoordinate (void) const final;
     double  timeBetweenShots    (void) final;
 
diff --git a/src/MissionManager/FWLandingPatternTest.cc b/src/MissionManager/FWLandingPatternTest.cc
index f86bebd05b65a2785b192003ae1a63dce21109b9..7e662dbf8fb1754aa88b80593ccec59987eca297 100644
--- a/src/MissionManager/FWLandingPatternTest.cc
+++ b/src/MissionManager/FWLandingPatternTest.cc
@@ -81,7 +81,7 @@ void FWLandingPatternTest::_testDirty(void)
 
 void FWLandingPatternTest::_testSaveLoad(void)
 {
-    QJsonObject items;
+    QJsonArray items;
 
     _fwItem->save(items);
 
diff --git a/src/MissionManager/FixedWingLandingComplexItem.cc b/src/MissionManager/FixedWingLandingComplexItem.cc
index 2da97f59452f1eef0d5da1cac959da919d8d6e69..486647360f11e88f5f501d78cc83b6fa2aec7093 100644
--- a/src/MissionManager/FixedWingLandingComplexItem.cc
+++ b/src/MissionManager/FixedWingLandingComplexItem.cc
@@ -60,7 +60,7 @@ FixedWingLandingComplexItem::FixedWingLandingComplexItem(PlanMasterController* m
     setDirty(false);
 }
 
-void FixedWingLandingComplexItem::save(QJsonObject&  missionItems)
+void FixedWingLandingComplexItem::save(QJsonArray&  missionItems)
 {
     QJsonObject saveObject = _save();
 
diff --git a/src/MissionManager/FixedWingLandingComplexItem.h b/src/MissionManager/FixedWingLandingComplexItem.h
index 812f62706bc2cc68d47e86b1263c7472bd6d0b3e..7316fa88e784a91b094963a21dec43caca9295bb 100644
--- a/src/MissionManager/FixedWingLandingComplexItem.h
+++ b/src/MissionManager/FixedWingLandingComplexItem.h
@@ -44,7 +44,7 @@ public:
     QString mapVisualQML        (void) const final { return QStringLiteral("FWLandingPatternMapVisual.qml"); }
 
     // Overrides from VisualMissionItem
-    void                save                        (QJsonObject&  missionItems) final;
+    void                save                        (QJsonArray&  missionItems) final;
 
     static const QString name;
 
diff --git a/src/MissionManager/GeoFenceController.cc b/src/MissionManager/GeoFenceController.cc
index db25fdc651e1db4b1f5e9d488158e88cacc3762d..4e3042d192e71e442a4add731916b7cdaa654d64 100644
--- a/src/MissionManager/GeoFenceController.cc
+++ b/src/MissionManager/GeoFenceController.cc
@@ -152,7 +152,7 @@ bool GeoFenceController::load(const QJsonObject& json, QString& errorString)
         return false;
     }
 
-    QJsonObject jsonPolygonArray = json[_jsonPolygonsKey].toArray();
+    QJsonArray jsonPolygonArray = json[_jsonPolygonsKey].toArray();
     for (const QJsonValue jsonPolygonValue: jsonPolygonArray) {
         if (jsonPolygonValue.type() != QJsonValue::Object) {
             errorString = tr("GeoFence polygon not stored as object");
@@ -166,7 +166,7 @@ bool GeoFenceController::load(const QJsonObject& json, QString& errorString)
         _polygons.append(fencePolygon);
     }
 
-    QJsonObject jsonCircleArray = json[_jsonCirclesKey].toArray();
+    QJsonArray jsonCircleArray = json[_jsonCirclesKey].toArray();
     for (const QJsonValue jsonCircleValue: jsonCircleArray) {
         if (jsonCircleValue.type() != QJsonValue::Object) {
             errorString = tr("GeoFence circle not stored as object");
@@ -200,7 +200,7 @@ void GeoFenceController::save(QJsonObject& json)
 {
     json[JsonHelper::jsonVersionKey] = _jsonCurrentVersion;
 
-    QJsonObject jsonPolygonArray;
+    QJsonArray jsonPolygonArray;
     for (int i=0; i<_polygons.count(); i++) {
         QJsonObject jsonPolygon;
         QGCFencePolygon* fencePolygon = _polygons.value<QGCFencePolygon*>(i);
@@ -209,7 +209,7 @@ void GeoFenceController::save(QJsonObject& json)
     }
     json[_jsonPolygonsKey] = jsonPolygonArray;
 
-    QJsonObject jsonCircleArray;
+    QJsonArray jsonCircleArray;
     for (int i=0; i<_circles.count(); i++) {
         QJsonObject jsonCircle;
         QGCFenceCircle* fenceCircle = _circles.value<QGCFenceCircle*>(i);
diff --git a/src/MissionManager/LandingComplexItemTest.h b/src/MissionManager/LandingComplexItemTest.h
index 347f2bef4223a9f2e84589bebaf3e5b67061e48d..cf32f823049bd9f0b4eaf33ac6bc6b9d23c76df5 100644
--- a/src/MissionManager/LandingComplexItemTest.h
+++ b/src/MissionManager/LandingComplexItemTest.h
@@ -82,7 +82,7 @@ public:
     QString mapVisualQML(void) const final { return QStringLiteral("FWLandingPatternMapVisual.qml"); }
 
     // Overrides from VisualMissionItem
-    void                save                        (QJsonObject&  /*missionItems*/) { };
+    void                save                        (QJsonArray&  /*missionItems*/) { };
 
     static const QString name;
 
diff --git a/src/MissionManager/MissionCommandList.cc b/src/MissionManager/MissionCommandList.cc
index 0bc4b203f3b4afb5faaf95f45701b935e1fd7881..5ca37136c841ec346b05a9e8642153ff1dcf4fbb 100644
--- a/src/MissionManager/MissionCommandList.cc
+++ b/src/MissionManager/MissionCommandList.cc
@@ -55,7 +55,7 @@ void MissionCommandList::_loadMavCmdInfoJson(const QString& jsonFilename, bool b
     }
 
     // Iterate over MissionCommandUIInfo objects
-    QJsonObject jsonArray = jsonValue.toArray();
+    QJsonArray jsonArray = jsonValue.toArray();
     for(QJsonValue info: jsonArray) {
         if (!info.isObject()) {
             qWarning() << jsonFilename << "mavCmdArray should contain objects";
diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc
index c5651b741ffec2644351b960af91068ba220a074..e69d87b7daa9fdba8bc740f663663f3579cbeaee 100644
--- a/src/MissionManager/MissionController.cc
+++ b/src/MissionManager/MissionController.cc
@@ -744,7 +744,7 @@ bool MissionController::_loadJsonMissionFileV1(const QJsonObject &json,
 
   // Read complex items
   QList<SurveyComplexItem *> surveyItems;
-  QJsonObject complexArray(json[_jsonComplexItemsKey].toArray());
+  QJsonArray complexArray(json[_jsonComplexItemsKey].toArray());
   qCDebug(MissionControllerLog)
       << "Json load: complex item count" << complexArray.count();
   for (int i = 0; i < complexArray.count(); i++) {
@@ -771,7 +771,7 @@ bool MissionController::_loadJsonMissionFileV1(const QJsonObject &json,
   int nextSimpleItemIndex = 0;
   int nextComplexItemIndex = 0;
   int nextSequenceNumber = 1; // Start with 1 since home is in 0
-  QJsonObject itemArray(json[_jsonItemsKey].toArray());
+  QJsonArray itemArray(json[_jsonItemsKey].toArray());
 
   MissionSettingsItem *settingsItem = _addMissionSettings(visualItems);
   if (json.contains(_jsonPlannedHomePositionKey)) {
@@ -932,7 +932,7 @@ bool MissionController::_loadJsonMissionFileV2(const QJsonObject &json,
   // Read mission items
 
   int nextSequenceNumber = 1; // Start with 1 since home is in 0
-  const QJsonObject rgMissionItems(json[_jsonItemsKey].toArray());
+  const QJsonArray rgMissionItems(json[_jsonItemsKey].toArray());
   for (int i = 0; i < rgMissionItems.count(); i++) {
     // Convert to QJsonObject
     const QJsonValue &itemValue = rgMissionItems[i];
@@ -1335,7 +1335,7 @@ void MissionController::save(QJsonObject &json) {
 
   // Save the visual items
 
-  QJsonObject rgJsonMissionItems;
+  QJsonArray rgJsonMissionItems;
   for (int i = 0; i < _visualItems->count(); i++) {
     VisualMissionItem *visualItem =
         qobject_cast<VisualMissionItem *>(_visualItems->get(i));
diff --git a/src/MissionManager/MissionItem.cc b/src/MissionManager/MissionItem.cc
index f9bad15527af2ed831a8b8ae397fe847348e23b9..3fb185546a789fc3082e1ae09a802199e854b1f8 100644
--- a/src/MissionManager/MissionItem.cc
+++ b/src/MissionManager/MissionItem.cc
@@ -147,7 +147,7 @@ void MissionItem::save(QJsonObject &json) const {
   json[_jsonAutoContinueKey] = autoContinue();
   json[_jsonDoJumpIdKey] = _sequenceNumber;
 
-  QJsonObject rgParams = {param1(), param2(), param3(), param4(),
+  QJsonArray rgParams = {param1(), param2(), param3(), param4(),
                          param5(), param6(), param7()};
   json[_jsonParamsKey] = rgParams;
 }
@@ -206,7 +206,7 @@ bool MissionItem::_convertJsonV1ToV2(const QJsonObject &json,
         VisualMissionItem::jsonTypeSimpleItemValue;
   }
 
-  QJsonObject rgParams = {
+  QJsonArray rgParams = {
       json[_jsonParam1Key].toDouble(), json[_jsonParam2Key].toDouble(),
       json[_jsonParam3Key].toDouble(), json[_jsonParam4Key].toDouble()};
   v2Json[_jsonParamsKey] = rgParams;
@@ -241,7 +241,7 @@ bool MissionItem::_convertJsonV2ToV3(QJsonObject &json, QString &errorString) {
     return false;
   }
 
-  QJsonObject rgParam = json[_jsonParamsKey].toArray();
+  QJsonArray rgParam = json[_jsonParamsKey].toArray();
   rgParam.append(coordinate.latitude());
   rgParam.append(coordinate.longitude());
   rgParam.append(coordinate.altitude());
@@ -283,7 +283,7 @@ bool MissionItem::load(const QJsonObject &json, int sequenceNumber,
     return false;
   }
 
-  QJsonObject rgParams = convertedJson[_jsonParamsKey].toArray();
+  QJsonArray rgParams = convertedJson[_jsonParamsKey].toArray();
   if (rgParams.count() != 7) {
     errorString = tr("%1 key must contains 7 values").arg(_jsonParamsKey);
     return false;
diff --git a/src/MissionManager/MissionItemTest.cc b/src/MissionManager/MissionItemTest.cc
index 45546e5507690bbb85858f1dee1a069d80d1a2fb..e2df716a21666becdf2a51b15481984dd8d41e91 100644
--- a/src/MissionManager/MissionItemTest.cc
+++ b/src/MissionManager/MissionItemTest.cc
@@ -342,7 +342,7 @@ void MissionItemTest::_testLoadFromJsonV2(void)
     QVERIFY(!errorString.isEmpty());
     qDebug() << errorString;
 
-    QJsonObject  badCoordinateArray;
+    QJsonArray  badCoordinateArray;
     badCoordinateArray << -10.0 << -20.0 ;
     badObject = jsonObject;
     badObject.remove("coordinate");
@@ -351,7 +351,7 @@ void MissionItemTest::_testLoadFromJsonV2(void)
     QVERIFY(!errorString.isEmpty());
     qDebug() << errorString;
 
-    QJsonObject badCoordinateArray_second;
+    QJsonArray badCoordinateArray_second;
     badCoordinateArray_second << -10.0 << -20.0 << true;
     badObject = jsonObject;
     badObject.remove("coordinate");
@@ -360,9 +360,9 @@ void MissionItemTest::_testLoadFromJsonV2(void)
     QVERIFY(!errorString.isEmpty());
     qDebug() << errorString;
 
-    QJsonObject  badCoordinateArray2;
+    QJsonArray  badCoordinateArray2;
     badCoordinateArray2 << 1 << 2;
-    QJsonObject badCoordinateArray_third;
+    QJsonArray badCoordinateArray_third;
     badCoordinateArray_third << -10.0 << -20.0 << badCoordinateArray2;
     badObject = jsonObject;
     badObject.remove("coordinate");
@@ -412,7 +412,7 @@ void MissionItemTest::_testLoadFromJsonV3(void)
 
     // Incorrect param count
     badObject = jsonObject;
-    QJsonObject rgParam = badObject[MissionItem::_jsonParamsKey].toArray();
+    QJsonArray rgParam = badObject[MissionItem::_jsonParamsKey].toArray();
     rgParam.removeFirst();
     badObject[MissionItem::_jsonParamsKey] = rgParam;
     QCOMPARE(missionItem.load(badObject, _seq, errorString), false);
@@ -450,7 +450,7 @@ void MissionItemTest::_testSimpleLoadFromJson(void)
 
     SimpleMissionItem simpleMissionItem(_masterController, false /* flyView */, false /* forLoad */, nullptr);
     QString     errorString;
-    QJsonObject  coordinateArray;
+    QJsonArray  coordinateArray;
     QJsonObject jsonObject;
 
     coordinateArray << -10.0 << -20.0 <<-30.0;
@@ -460,7 +460,7 @@ void MissionItemTest::_testSimpleLoadFromJson(void)
     jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue);
     jsonObject.insert(MissionItem::_jsonCoordinateKey, coordinateArray);
 
-    QJsonObject rgParams =  { 10, 20, 30, 40 };
+    QJsonArray rgParams =  { 10, 20, 30, 40 };
     jsonObject.insert(MissionItem::_jsonParamsKey, rgParams);
 
     QVERIFY(simpleMissionItem.load(jsonObject, _seq, errorString));
@@ -489,7 +489,7 @@ void MissionItemTest::_testSaveToJson(void)
 QJsonObject MissionItemTest::_createV1Json(void)
 {
     QJsonObject jsonObject;
-    QJsonObject  coordinateArray;
+    QJsonArray  coordinateArray;
 
     coordinateArray << -10.0 << -20.0 <<-30.0;
     jsonObject.insert(MissionItem::_jsonAutoContinueKey, true);
@@ -508,7 +508,7 @@ QJsonObject MissionItemTest::_createV1Json(void)
 QJsonObject MissionItemTest::_createV2Json(void)
 {
     QJsonObject jsonObject;
-    QJsonObject  coordinateArray;
+    QJsonArray  coordinateArray;
 
     coordinateArray << -10.0 << -20.0 <<-30.0;
     jsonObject.insert(MissionItem::_jsonAutoContinueKey, true);
@@ -517,7 +517,7 @@ QJsonObject MissionItemTest::_createV2Json(void)
     jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue);
     jsonObject.insert(MissionItem::_jsonCoordinateKey, coordinateArray);
 
-    QJsonObject rgParams =  { 10, 20, 30, 40 };
+    QJsonArray rgParams =  { 10, 20, 30, 40 };
     jsonObject.insert(MissionItem::_jsonParamsKey, rgParams);
 
     return jsonObject;
@@ -533,10 +533,10 @@ QJsonObject MissionItemTest::_createV3Json(bool allNaNs)
     jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue);
 
     if (allNaNs) {
-        QJsonObject rgParams =  { NAN, NAN, NAN, NAN, NAN, NAN, NAN };
+        QJsonArray rgParams =  { NAN, NAN, NAN, NAN, NAN, NAN, NAN };
         jsonObject.insert(MissionItem::_jsonParamsKey, rgParams);
     } else {
-        QJsonObject rgParams =  { 10, 20, 30, 40, -10, -20, -30 };
+        QJsonArray rgParams =  { 10, 20, 30, 40, -10, -20, -30 };
         jsonObject.insert(MissionItem::_jsonParamsKey, rgParams);
     }
 
diff --git a/src/MissionManager/MissionSettingsItem.cc b/src/MissionManager/MissionSettingsItem.cc
index 326eb86c3193dac48bddd0a874825e91464fbb7f..fceba9d1d7c34b75a0e4ed6bd455d087d30c7e1d 100644
--- a/src/MissionManager/MissionSettingsItem.cc
+++ b/src/MissionManager/MissionSettingsItem.cc
@@ -88,7 +88,7 @@ void MissionSettingsItem::setDirty(bool dirty)
     }
 }
 
-void MissionSettingsItem::save(QJsonObject&  missionItems)
+void MissionSettingsItem::save(QJsonArray&  missionItems)
 {
     QList<MissionItem*> items;
 
diff --git a/src/MissionManager/MissionSettingsItem.h b/src/MissionManager/MissionSettingsItem.h
index 824dea40d4051553b51a613d072ef139d6a91617..921225c088c4d23b9745cec290db9032f7d27c07 100644
--- a/src/MissionManager/MissionSettingsItem.h
+++ b/src/MissionManager/MissionSettingsItem.h
@@ -87,7 +87,7 @@ public:
     void            setDirty                    (bool dirty) final;
     void            setCoordinate               (const QGeoCoordinate& coordinate) final;   // Should only be called if the end user is moving
     void            setSequenceNumber           (int sequenceNumber) final;
-    void            save                        (QJsonObject&  missionItems) final;
+    void            save                        (QJsonArray&  missionItems) final;
     double          amslEntryAlt                (void) const final { return _plannedHomePositionCoordinate.altitude(); }
     double          amslExitAlt                 (void) const final { return amslEntryAlt(); }
     double          minAMSLAltitude             (void) const final { return amslEntryAlt(); }
diff --git a/src/MissionManager/RallyPointController.cc b/src/MissionManager/RallyPointController.cc
index 8faa00d0e0a9c3a983a907ce8329e9d128a38c39..77be144488159873bc98485c35761ee0fd28f067 100644
--- a/src/MissionManager/RallyPointController.cc
+++ b/src/MissionManager/RallyPointController.cc
@@ -128,7 +128,7 @@ void RallyPointController::save(QJsonObject& json)
 {
     json[JsonHelper::jsonVersionKey] = _jsonCurrentVersion;
 
-    QJsonObject rgPoints;
+    QJsonArray rgPoints;
     QJsonValue jsonPoint;
     for (int i=0; i<_points.count(); i++) {
         JsonHelper::saveGeoCoordinate(qobject_cast<RallyPoint*>(_points[i])->coordinate(), true /* writeAltitude */, jsonPoint);
diff --git a/src/MissionManager/SimpleMissionItem.cc b/src/MissionManager/SimpleMissionItem.cc
index 14f1eff3b2abe73c68faba13b1cb79ede4552725..a1b4c70e8af9efabeffd875f30691885bc03d8e4 100644
--- a/src/MissionManager/SimpleMissionItem.cc
+++ b/src/MissionManager/SimpleMissionItem.cc
@@ -260,7 +260,7 @@ SimpleMissionItem::~SimpleMissionItem()
 {    
 }
 
-void SimpleMissionItem::save(QJsonObject&  missionItems)
+void SimpleMissionItem::save(QJsonArray&  missionItems)
 {
     QList<MissionItem*> items;
 
diff --git a/src/MissionManager/SimpleMissionItem.h b/src/MissionManager/SimpleMissionItem.h
index 6fd358bfecf82f4a60defa74ed717f797ae7b00e..fd33ad4c341f66166dba827f99bc46882c87e6bc 100644
--- a/src/MissionManager/SimpleMissionItem.h
+++ b/src/MissionManager/SimpleMissionItem.h
@@ -127,7 +127,7 @@ public:
     void setCoordinate      (const QGeoCoordinate& coordinate) override;
     void setSequenceNumber  (int sequenceNumber) final;
     int  lastSequenceNumber (void) const final;
-    void save               (QJsonObject&  missionItems) final;
+    void save               (QJsonArray&  missionItems) final;
 
 signals:
     void commandChanged             (int command);
diff --git a/src/MissionManager/StructureScanComplexItem.cc b/src/MissionManager/StructureScanComplexItem.cc
index 580f1c28829a480531cbec72b98d01d6f414c5ad..db9d933c0c2d28f05f539abe9138d96b00f5d71b 100644
--- a/src/MissionManager/StructureScanComplexItem.cc
+++ b/src/MissionManager/StructureScanComplexItem.cc
@@ -177,7 +177,7 @@ void StructureScanComplexItem::setDirty(bool dirty)
     }
 }
 
-void StructureScanComplexItem::save(QJsonObject&  missionItems)
+void StructureScanComplexItem::save(QJsonArray&  missionItems)
 {
     QJsonObject saveObject;
 
diff --git a/src/MissionManager/StructureScanComplexItem.h b/src/MissionManager/StructureScanComplexItem.h
index 93916b8d17bf47e501e5ade32859da53cb169fbd..d99f4d9f7165efac1a08cc4788893d0fac22a26e 100644
--- a/src/MissionManager/StructureScanComplexItem.h
+++ b/src/MissionManager/StructureScanComplexItem.h
@@ -94,7 +94,7 @@ public:
     void                setDirty                    (bool dirty) final;
     void                setCoordinate               (const QGeoCoordinate& coordinate) final { Q_UNUSED(coordinate); }
     void                setSequenceNumber           (int sequenceNumber) final;
-    void                save                        (QJsonObject&  missionItems) final;
+    void                save                        (QJsonArray&  missionItems) final;
     double              amslEntryAlt                (void) const final;
     double              amslExitAlt                 (void) const final { return amslEntryAlt(); };
     double              minAMSLAltitude             (void) const final;
diff --git a/src/MissionManager/StructureScanComplexItemTest.cc b/src/MissionManager/StructureScanComplexItemTest.cc
index 5fd8e51535d3b524f5ecdfc85bc51fa3e1134e57..db3c06e9a50d399f031b429f6d1e8e93053f3d4f 100644
--- a/src/MissionManager/StructureScanComplexItemTest.cc
+++ b/src/MissionManager/StructureScanComplexItemTest.cc
@@ -110,7 +110,7 @@ void StructureScanComplexItemTest::_testSaveLoad(void)
 {
     _initItem();
 
-    QJsonObject  items;
+    QJsonArray  items;
     _structureScanItem->save(items);
 
     QString errorString;
diff --git a/src/MissionManager/SurveyComplexItem.cc b/src/MissionManager/SurveyComplexItem.cc
index c5e7621d24d3d84b957fa7c0978434b1f3156fd0..3096dab60bb3f865fe3d0baca48b10699d4c4ef5 100644
--- a/src/MissionManager/SurveyComplexItem.cc
+++ b/src/MissionManager/SurveyComplexItem.cc
@@ -7,15 +7,16 @@
  *
  ****************************************************************************/
 
+
 #include "SurveyComplexItem.h"
-#include "AppSettings.h"
 #include "JsonHelper.h"
 #include "MissionController.h"
-#include "PlanMasterController.h"
-#include "QGCApplication.h"
 #include "QGCGeo.h"
 #include "QGCQGeoCoordinate.h"
 #include "SettingsManager.h"
+#include "AppSettings.h"
+#include "PlanMasterController.h"
+#include "QGCApplication.h"
 
 #include <QPolygonF>
 
@@ -23,1625 +24,1417 @@ QGC_LOGGING_CATEGORY(SurveyComplexItemLog, "SurveyComplexItemLog")
 
 const QString SurveyComplexItem::name(tr("Survey"));
 
-const char *SurveyComplexItem::jsonComplexItemTypeValue = "survey";
-const char *SurveyComplexItem::jsonV3ComplexItemTypeValue = "survey";
-
-const char *SurveyComplexItem::settingsGroup = "Survey";
-const char *SurveyComplexItem::gridAngleName = "GridAngle";
-const char *SurveyComplexItem::gridEntryLocationName = "GridEntryLocation";
-const char *SurveyComplexItem::flyAlternateTransectsName =
-    "FlyAlternateTransects";
-const char *SurveyComplexItem::splitConcavePolygonsName =
-    "SplitConcavePolygons";
-
-const char *SurveyComplexItem::_jsonGridAngleKey = "angle";
-const char *SurveyComplexItem::_jsonEntryPointKey = "entryLocation";
-
-const char *SurveyComplexItem::_jsonV3GridObjectKey = "grid";
-const char *SurveyComplexItem::_jsonV3GridAltitudeKey = "altitude";
-const char *SurveyComplexItem::_jsonV3GridAltitudeRelativeKey =
-    "relativeAltitude";
-const char *SurveyComplexItem::_jsonV3GridAngleKey = "angle";
-const char *SurveyComplexItem::_jsonV3GridSpacingKey = "spacing";
-const char *SurveyComplexItem::_jsonV3EntryPointKey = "entryLocation";
-const char *SurveyComplexItem::_jsonV3TurnaroundDistKey = "turnAroundDistance";
-const char *SurveyComplexItem::_jsonV3CameraTriggerDistanceKey =
-    "cameraTriggerDistance";
-const char *SurveyComplexItem::_jsonV3CameraTriggerInTurnaroundKey =
-    "cameraTriggerInTurnaround";
-const char *SurveyComplexItem::_jsonV3HoverAndCaptureKey = "hoverAndCapture";
-const char *SurveyComplexItem::_jsonV3GroundResolutionKey = "groundResolution";
-const char *SurveyComplexItem::_jsonV3FrontalOverlapKey = "imageFrontalOverlap";
-const char *SurveyComplexItem::_jsonV3SideOverlapKey = "imageSideOverlap";
-const char *SurveyComplexItem::_jsonV3CameraSensorWidthKey = "sensorWidth";
-const char *SurveyComplexItem::_jsonV3CameraSensorHeightKey = "sensorHeight";
-const char *SurveyComplexItem::_jsonV3CameraResolutionWidthKey =
-    "resolutionWidth";
-const char *SurveyComplexItem::_jsonV3CameraResolutionHeightKey =
-    "resolutionHeight";
-const char *SurveyComplexItem::_jsonV3CameraFocalLengthKey = "focalLength";
-const char *SurveyComplexItem::_jsonV3CameraMinTriggerIntervalKey =
-    "minTriggerInterval";
-const char *SurveyComplexItem::_jsonV3CameraObjectKey = "camera";
-const char *SurveyComplexItem::_jsonV3CameraNameKey = "name";
-const char *SurveyComplexItem::_jsonV3ManualGridKey = "manualGrid";
-const char *SurveyComplexItem::_jsonV3CameraOrientationLandscapeKey =
-    "orientationLandscape";
-const char *SurveyComplexItem::_jsonV3FixedValueIsAltitudeKey =
-    "fixedValueIsAltitude";
-const char *SurveyComplexItem::_jsonV3Refly90DegreesKey = "refly90Degrees";
-const char *SurveyComplexItem::_jsonFlyAlternateTransectsKey =
-    "flyAlternateTransects";
-const char *SurveyComplexItem::_jsonSplitConcavePolygonsKey =
-    "splitConcavePolygons";
-
-SurveyComplexItem::SurveyComplexItem(PlanMasterController *masterController,
-                                     bool flyView, const QString &kmlOrShpFile,
-                                     QObject *parent)
-    : TransectStyleComplexItem(masterController, flyView, settingsGroup,
-                               parent),
-      _metaDataMap(FactMetaData::createMapFromJsonFile(
-          QStringLiteral(":/json/Survey.SettingsGroup.json"), this)),
-      _gridAngleFact(settingsGroup, _metaDataMap[gridAngleName]),
-      _flyAlternateTransectsFact(settingsGroup,
-                                 _metaDataMap[flyAlternateTransectsName]),
-      _splitConcavePolygonsFact(settingsGroup,
-                                _metaDataMap[splitConcavePolygonsName]),
-      _entryPoint(EntryLocationTopLeft) {
-  _editorQml = "qrc:/qml/SurveyItemEditor.qml";
-
-  // If the user hasn't changed turnaround from the default (which is a fixed
-  // wing default) and we are multi-rotor set the multi-rotor default. NULL
-  // check since object creation during unit testing passes NULL for vehicle
-  if (_controllerVehicle && _controllerVehicle->multiRotor() &&
-      _turnAroundDistanceFact.rawValue().toDouble() ==
-          _turnAroundDistanceFact.rawDefaultValue().toDouble()) {
-    // Note this is set to 10 meters to work around a problem with PX4 Pro
-    // turnaround behavior. Don't change unless firmware gets better as well.
-    _turnAroundDistanceFact.setRawValue(10);
-  }
-
-  if (_controllerVehicle &&
-      !(_controllerVehicle->fixedWing() || _controllerVehicle->vtol())) {
-    // Only fixed wing flight paths support alternate transects
-    _flyAlternateTransectsFact.setRawValue(false);
-  }
-
-  // We override the altitude to the mission default
-  if (_cameraCalc.isManualCamera() ||
-      !_cameraCalc.valueSetIsDistance()->rawValue().toBool()) {
-    _cameraCalc.distanceToSurface()->setRawValue(
-        qgcApp()
-            ->toolbox()
-            ->settingsManager()
-            ->appSettings()
-            ->defaultMissionItemAltitude()
-            ->rawValue());
-  }
-
-  connect(&_gridAngleFact, &Fact::valueChanged, this,
-          &SurveyComplexItem::_setDirty);
-  connect(&_flyAlternateTransectsFact, &Fact::valueChanged, this,
-          &SurveyComplexItem::_setDirty);
-  connect(&_splitConcavePolygonsFact, &Fact::valueChanged, this,
-          &SurveyComplexItem::_setDirty);
-  connect(this, &SurveyComplexItem::refly90DegreesChanged, this,
-          &SurveyComplexItem::_setDirty);
-
-  connect(&_gridAngleFact, &Fact::valueChanged, this,
-          &SurveyComplexItem::_rebuildTransects);
-  connect(&_flyAlternateTransectsFact, &Fact::valueChanged, this,
-          &SurveyComplexItem::_rebuildTransects);
-  connect(&_splitConcavePolygonsFact, &Fact::valueChanged, this,
-          &SurveyComplexItem::_rebuildTransects);
-  connect(this, &SurveyComplexItem::refly90DegreesChanged, this,
-          &SurveyComplexItem::_rebuildTransects);
-
-  connect(&_surveyAreaPolygon, &QGCMapPolygon::isValidChanged, this,
-          &SurveyComplexItem::_updateWizardMode);
-  connect(&_surveyAreaPolygon, &QGCMapPolygon::traceModeChanged, this,
-          &SurveyComplexItem::_updateWizardMode);
-
-  if (!kmlOrShpFile.isEmpty()) {
-    _surveyAreaPolygon.loadKMLOrSHPFile(kmlOrShpFile);
-    _surveyAreaPolygon.setDirty(false);
-  }
-  setDirty(false);
-}
+const char* SurveyComplexItem::jsonComplexItemTypeValue =   "survey";
+const char* SurveyComplexItem::jsonV3ComplexItemTypeValue = "survey";
+
+const char* SurveyComplexItem::settingsGroup =              "Survey";
+const char* SurveyComplexItem::gridAngleName =              "GridAngle";
+const char* SurveyComplexItem::gridEntryLocationName =      "GridEntryLocation";
+const char* SurveyComplexItem::flyAlternateTransectsName =  "FlyAlternateTransects";
+const char* SurveyComplexItem::splitConcavePolygonsName =   "SplitConcavePolygons";
+
+const char* SurveyComplexItem::_jsonGridAngleKey =          "angle";
+const char* SurveyComplexItem::_jsonEntryPointKey =         "entryLocation";
+
+const char* SurveyComplexItem::_jsonV3GridObjectKey =                   "grid";
+const char* SurveyComplexItem::_jsonV3GridAltitudeKey =                 "altitude";
+const char* SurveyComplexItem::_jsonV3GridAltitudeRelativeKey =         "relativeAltitude";
+const char* SurveyComplexItem::_jsonV3GridAngleKey =                    "angle";
+const char* SurveyComplexItem::_jsonV3GridSpacingKey =                  "spacing";
+const char* SurveyComplexItem::_jsonV3EntryPointKey =                   "entryLocation";
+const char* SurveyComplexItem::_jsonV3TurnaroundDistKey =               "turnAroundDistance";
+const char* SurveyComplexItem::_jsonV3CameraTriggerDistanceKey =        "cameraTriggerDistance";
+const char* SurveyComplexItem::_jsonV3CameraTriggerInTurnaroundKey =    "cameraTriggerInTurnaround";
+const char* SurveyComplexItem::_jsonV3HoverAndCaptureKey =              "hoverAndCapture";
+const char* SurveyComplexItem::_jsonV3GroundResolutionKey =             "groundResolution";
+const char* SurveyComplexItem::_jsonV3FrontalOverlapKey =               "imageFrontalOverlap";
+const char* SurveyComplexItem::_jsonV3SideOverlapKey =                  "imageSideOverlap";
+const char* SurveyComplexItem::_jsonV3CameraSensorWidthKey =            "sensorWidth";
+const char* SurveyComplexItem::_jsonV3CameraSensorHeightKey =           "sensorHeight";
+const char* SurveyComplexItem::_jsonV3CameraResolutionWidthKey =        "resolutionWidth";
+const char* SurveyComplexItem::_jsonV3CameraResolutionHeightKey =       "resolutionHeight";
+const char* SurveyComplexItem::_jsonV3CameraFocalLengthKey =            "focalLength";
+const char* SurveyComplexItem::_jsonV3CameraMinTriggerIntervalKey =     "minTriggerInterval";
+const char* SurveyComplexItem::_jsonV3CameraObjectKey =                 "camera";
+const char* SurveyComplexItem::_jsonV3CameraNameKey =                   "name";
+const char* SurveyComplexItem::_jsonV3ManualGridKey =                   "manualGrid";
+const char* SurveyComplexItem::_jsonV3CameraOrientationLandscapeKey =   "orientationLandscape";
+const char* SurveyComplexItem::_jsonV3FixedValueIsAltitudeKey =         "fixedValueIsAltitude";
+const char* SurveyComplexItem::_jsonV3Refly90DegreesKey =               "refly90Degrees";
+const char* SurveyComplexItem::_jsonFlyAlternateTransectsKey =          "flyAlternateTransects";
+const char* SurveyComplexItem::_jsonSplitConcavePolygonsKey =           "splitConcavePolygons";
+
+SurveyComplexItem::SurveyComplexItem(PlanMasterController* masterController, bool flyView, const QString& kmlOrShpFile, QObject* parent)
+    : TransectStyleComplexItem  (masterController, flyView, settingsGroup, parent)
+    , _metaDataMap              (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/Survey.SettingsGroup.json"), this))
+    , _gridAngleFact            (settingsGroup, _metaDataMap[gridAngleName])
+    , _flyAlternateTransectsFact(settingsGroup, _metaDataMap[flyAlternateTransectsName])
+    , _splitConcavePolygonsFact (settingsGroup, _metaDataMap[splitConcavePolygonsName])
+    , _entryPoint               (EntryLocationTopLeft)
+{
+    _editorQml = "qrc:/qml/SurveyItemEditor.qml";
+
+    // If the user hasn't changed turnaround from the default (which is a fixed wing default) and we are multi-rotor set the multi-rotor default.
+    // NULL check since object creation during unit testing passes NULL for vehicle
+    if (_controllerVehicle && _controllerVehicle->multiRotor() && _turnAroundDistanceFact.rawValue().toDouble() == _turnAroundDistanceFact.rawDefaultValue().toDouble()) {
+        // Note this is set to 10 meters to work around a problem with PX4 Pro turnaround behavior. Don't change unless firmware gets better as well.
+        _turnAroundDistanceFact.setRawValue(10);
+    }
 
-void SurveyComplexItem::save(QJsonObject &planItems) {
-  QJsonObject saveObject;
+    if (_controllerVehicle && !(_controllerVehicle->fixedWing() || _controllerVehicle->vtol())) {
+        // Only fixed wing flight paths support alternate transects
+        _flyAlternateTransectsFact.setRawValue(false);
+    }
+
+    // We override the altitude to the mission default
+    if (_cameraCalc.isManualCamera() || !_cameraCalc.valueSetIsDistance()->rawValue().toBool()) {
+        _cameraCalc.distanceToSurface()->setRawValue(qgcApp()->toolbox()->settingsManager()->appSettings()->defaultMissionItemAltitude()->rawValue());
+    }
+
+    connect(&_gridAngleFact,            &Fact::valueChanged,                        this, &SurveyComplexItem::_setDirty);
+    connect(&_flyAlternateTransectsFact,&Fact::valueChanged,                        this, &SurveyComplexItem::_setDirty);
+    connect(&_splitConcavePolygonsFact, &Fact::valueChanged,                        this, &SurveyComplexItem::_setDirty);
+    connect(this,                       &SurveyComplexItem::refly90DegreesChanged,  this, &SurveyComplexItem::_setDirty);
 
-  _saveWorker(saveObject);
-  planItems.append(saveObject);
+    connect(&_gridAngleFact,            &Fact::valueChanged,                        this, &SurveyComplexItem::_rebuildTransects);
+    connect(&_flyAlternateTransectsFact,&Fact::valueChanged,                        this, &SurveyComplexItem::_rebuildTransects);
+    connect(&_splitConcavePolygonsFact, &Fact::valueChanged,                        this, &SurveyComplexItem::_rebuildTransects);
+    connect(this,                       &SurveyComplexItem::refly90DegreesChanged,  this, &SurveyComplexItem::_rebuildTransects);
+
+    connect(&_surveyAreaPolygon,        &QGCMapPolygon::isValidChanged,             this, &SurveyComplexItem::_updateWizardMode);
+    connect(&_surveyAreaPolygon,        &QGCMapPolygon::traceModeChanged,           this, &SurveyComplexItem::_updateWizardMode);
+
+    if (!kmlOrShpFile.isEmpty()) {
+        _surveyAreaPolygon.loadKMLOrSHPFile(kmlOrShpFile);
+        _surveyAreaPolygon.setDirty(false);
+    }
+    setDirty(false);
 }
 
-void SurveyComplexItem::savePreset(const QString &name) {
-  QJsonObject saveObject;
+void SurveyComplexItem::save(QJsonArray&  planItems)
+{
+    QJsonObject saveObject;
 
-  _saveWorker(saveObject);
-  _savePresetJson(name, saveObject);
+    _saveWorker(saveObject);
+    planItems.append(saveObject);
 }
 
-void SurveyComplexItem::_saveWorker(QJsonObject &saveObject) {
-  TransectStyleComplexItem::_save(saveObject);
-
-  saveObject[JsonHelper::jsonVersionKey] = 5;
-  saveObject[VisualMissionItem::jsonTypeKey] =
-      VisualMissionItem::jsonTypeComplexItemValue;
-  saveObject[ComplexMissionItem::jsonComplexItemTypeKey] =
-      jsonComplexItemTypeValue;
-  saveObject[_jsonGridAngleKey] = _gridAngleFact.rawValue().toDouble();
-  saveObject[_jsonFlyAlternateTransectsKey] =
-      _flyAlternateTransectsFact.rawValue().toBool();
-  saveObject[_jsonSplitConcavePolygonsKey] =
-      _splitConcavePolygonsFact.rawValue().toBool();
-  saveObject[_jsonEntryPointKey] = _entryPoint;
-
-  // Polygon shape
-  _surveyAreaPolygon.saveToJson(saveObject);
+void SurveyComplexItem::savePreset(const QString& name)
+{
+    QJsonObject saveObject;
+
+    _saveWorker(saveObject);
+    _savePresetJson(name, saveObject);
 }
 
-void SurveyComplexItem::loadPreset(const QString &name) {
-  QString errorString;
-
-  QJsonObject presetObject = _loadPresetJson(name);
-  if (!_loadV4V5(presetObject, 0, errorString, 5, true /* forPresets */)) {
-    qgcApp()->showAppMessage(
-        QStringLiteral("Internal Error: Preset load failed. Name: %1 Error: %2")
-            .arg(name)
-            .arg(errorString));
-  }
-  _rebuildTransects();
+void SurveyComplexItem::_saveWorker(QJsonObject& saveObject)
+{
+    TransectStyleComplexItem::_save(saveObject);
+
+    saveObject[JsonHelper::jsonVersionKey] =                    5;
+    saveObject[VisualMissionItem::jsonTypeKey] =                VisualMissionItem::jsonTypeComplexItemValue;
+    saveObject[ComplexMissionItem::jsonComplexItemTypeKey] =    jsonComplexItemTypeValue;
+    saveObject[_jsonGridAngleKey] =                             _gridAngleFact.rawValue().toDouble();
+    saveObject[_jsonFlyAlternateTransectsKey] =                 _flyAlternateTransectsFact.rawValue().toBool();
+    saveObject[_jsonSplitConcavePolygonsKey] =                  _splitConcavePolygonsFact.rawValue().toBool();
+    saveObject[_jsonEntryPointKey] =                            _entryPoint;
+
+    // Polygon shape
+    _surveyAreaPolygon.saveToJson(saveObject);
 }
 
-bool SurveyComplexItem::load(const QJsonObject &complexObject,
-                             int sequenceNumber, QString &errorString) {
-  // 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, versionKeyInfoList,
-                                errorString)) {
-    return false;
-  }
-
-  int version = complexObject[JsonHelper::jsonVersionKey].toInt();
-  if (version < 2 || version > 5) {
-    errorString = tr("Survey items do not support version %1").arg(version);
-    return false;
-  }
-
-  if (version == 4 || version == 5) {
-    if (!_loadV4V5(complexObject, sequenceNumber, errorString, version,
-                   false /* forPresets */)) {
-      return false;
-    }
-
-    _recalcComplexDistance();
-    if (_cameraShots == 0) {
-      // Shot count was possibly not available from plan file
-      _recalcCameraShots();
-    }
-  } else {
-    // Must be v2 or v3
-    QJsonObject v3ComplexObject = complexObject;
-    if (version == 2) {
-      // Convert to v3
-      if (v3ComplexObject.contains(VisualMissionItem::jsonTypeKey) &&
-          v3ComplexObject[VisualMissionItem::jsonTypeKey].toString() ==
-              QStringLiteral("survey")) {
-        v3ComplexObject[VisualMissionItem::jsonTypeKey] =
-            VisualMissionItem::jsonTypeComplexItemValue;
-        v3ComplexObject[ComplexMissionItem::jsonComplexItemTypeKey] =
-            jsonComplexItemTypeValue;
-      }
-    }
-    if (!_loadV3(complexObject, sequenceNumber, errorString)) {
-      return false;
-    }
-
-    // V2/3 doesn't include individual items so we need to rebuild manually
+void SurveyComplexItem::loadPreset(const QString& name)
+{
+    QString errorString;
+
+    QJsonObject presetObject = _loadPresetJson(name);
+    if (!_loadV4V5(presetObject, 0, errorString, 5, true /* forPresets */)) {
+        qgcApp()->showAppMessage(QStringLiteral("Internal Error: Preset load failed. Name: %1 Error: %2").arg(name).arg(errorString));
+    }
     _rebuildTransects();
-  }
+}
+
+bool SurveyComplexItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
+{
+    // 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, versionKeyInfoList, errorString)) {
+        return false;
+    }
+
+    int version = complexObject[JsonHelper::jsonVersionKey].toInt();
+    if (version < 2 || version > 5) {
+        errorString = tr("Survey items do not support version %1").arg(version);
+        return false;
+    }
+
+    if (version == 4 || version == 5) {
+        if (!_loadV4V5(complexObject, sequenceNumber, errorString, version, false /* forPresets */)) {
+            return false;
+        }
+
+        _recalcComplexDistance();
+        if (_cameraShots == 0) {
+            // Shot count was possibly not available from plan file
+            _recalcCameraShots();
+        }
+    } else {
+        // Must be v2 or v3
+        QJsonObject v3ComplexObject = complexObject;
+        if (version == 2) {
+            // Convert to v3
+            if (v3ComplexObject.contains(VisualMissionItem::jsonTypeKey) && v3ComplexObject[VisualMissionItem::jsonTypeKey].toString() == QStringLiteral("survey")) {
+                v3ComplexObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
+                v3ComplexObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
+            }
+        }
+        if (!_loadV3(complexObject, sequenceNumber, errorString)) {
+            return false;
+        }
+
+        // V2/3 doesn't include individual items so we need to rebuild manually
+        _rebuildTransects();
+    }
 
-  return true;
+    return true;
 }
 
-bool SurveyComplexItem::_loadV4V5(const QJsonObject &complexObject,
-                                  int sequenceNumber, QString &errorString,
-                                  int version, bool forPresets) {
-  QList<JsonHelper::KeyValidateInfo> keyInfoList = {
-      {VisualMissionItem::jsonTypeKey, QJsonValue::String, true},
-      {ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true},
-      {_jsonEntryPointKey, QJsonValue::Double, true},
-      {_jsonGridAngleKey, QJsonValue::Double, true},
-      {_jsonFlyAlternateTransectsKey, QJsonValue::Bool, false},
-  };
-
-  if (version == 5) {
-    JsonHelper::KeyValidateInfo jSplitPolygon = {_jsonSplitConcavePolygonsKey,
-                                                 QJsonValue::Bool, true};
-    keyInfoList.append(jSplitPolygon);
-  }
-
-  if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) {
-    return false;
-  }
-
-  QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
-  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);
-    return false;
-  }
-
-  _ignoreRecalc = !forPresets;
-
-  if (!forPresets) {
-    setSequenceNumber(sequenceNumber);
+bool SurveyComplexItem::_loadV4V5(const QJsonObject& complexObject, int sequenceNumber, QString& errorString, int version, bool forPresets)
+{
+    QList<JsonHelper::KeyValidateInfo> keyInfoList = {
+        { VisualMissionItem::jsonTypeKey,               QJsonValue::String, true },
+        { ComplexMissionItem::jsonComplexItemTypeKey,   QJsonValue::String, true },
+        { _jsonEntryPointKey,                           QJsonValue::Double, true },
+        { _jsonGridAngleKey,                            QJsonValue::Double, true },
+        { _jsonFlyAlternateTransectsKey,                QJsonValue::Bool,   false },
+    };
 
-    if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */,
-                                         errorString)) {
-      _surveyAreaPolygon.clear();
-      return false;
+    if(version == 5) {
+        JsonHelper::KeyValidateInfo jSplitPolygon = { _jsonSplitConcavePolygonsKey, QJsonValue::Bool, true };
+        keyInfoList.append(jSplitPolygon);
     }
-  }
 
-  if (!TransectStyleComplexItem::_load(complexObject, forPresets,
-                                       errorString)) {
-    _ignoreRecalc = false;
-    return false;
-  }
+    if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) {
+        return false;
+    }
 
-  _gridAngleFact.setRawValue(complexObject[_jsonGridAngleKey].toDouble());
-  _flyAlternateTransectsFact.setRawValue(
-      complexObject[_jsonFlyAlternateTransectsKey].toBool(false));
+    QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
+    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);
+        return false;
+    }
 
-  if (version == 5) {
-    _splitConcavePolygonsFact.setRawValue(
-        complexObject[_jsonSplitConcavePolygonsKey].toBool(true));
-  }
+    _ignoreRecalc = !forPresets;
 
-  _entryPoint = complexObject[_jsonEntryPointKey].toInt();
+    if (!forPresets) {
+        setSequenceNumber(sequenceNumber);
 
-  _ignoreRecalc = false;
+        if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */, errorString)) {
+            _surveyAreaPolygon.clear();
+            return false;
+        }
+    }
 
-  return true;
-}
+    if (!TransectStyleComplexItem::_load(complexObject, forPresets, errorString)) {
+        _ignoreRecalc = false;
+        return false;
+    }
+
+    _gridAngleFact.setRawValue              (complexObject[_jsonGridAngleKey].toDouble());
+    _flyAlternateTransectsFact.setRawValue  (complexObject[_jsonFlyAlternateTransectsKey].toBool(false));
+
+    if (version == 5) {
+        _splitConcavePolygonsFact.setRawValue   (complexObject[_jsonSplitConcavePolygonsKey].toBool(true));
+    }
+
+    _entryPoint = complexObject[_jsonEntryPointKey].toInt();
 
-bool SurveyComplexItem::_loadV3(const QJsonObject &complexObject,
-                                int sequenceNumber, QString &errorString) {
-  QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
-      {VisualMissionItem::jsonTypeKey, QJsonValue::String, true},
-      {ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true},
-      {QGCMapPolygon::jsonPolygonKey, QJsonValue::Array, true},
-      {_jsonV3GridObjectKey, QJsonValue::Object, true},
-      {_jsonV3CameraObjectKey, QJsonValue::Object, false},
-      {_jsonV3CameraTriggerDistanceKey, QJsonValue::Double, true},
-      {_jsonV3ManualGridKey, QJsonValue::Bool, true},
-      {_jsonV3FixedValueIsAltitudeKey, QJsonValue::Bool, true},
-      {_jsonV3HoverAndCaptureKey, QJsonValue::Bool, false},
-      {_jsonV3Refly90DegreesKey, QJsonValue::Bool, false},
-      {_jsonV3CameraTriggerInTurnaroundKey, QJsonValue::Bool,
-       false}, // Should really be required, but it was missing from initial
-               // code due to bug
-  };
-  if (!JsonHelper::validateKeys(complexObject, mainKeyInfoList, errorString)) {
-    return false;
-  }
-
-  QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
-  QString complexType =
-      complexObject[ComplexMissionItem::jsonComplexItemTypeKey].toString();
-  if (itemType != VisualMissionItem::jsonTypeComplexItemValue ||
-      complexType != jsonV3ComplexItemTypeValue) {
-    errorString =
-        tr("%1 does not support loading this complex mission item type: %2:%3")
-            .arg(qgcApp()->applicationName())
-            .arg(itemType)
-            .arg(complexType);
-    return false;
-  }
-
-  _ignoreRecalc = true;
-
-  setSequenceNumber(sequenceNumber);
-
-  _hoverAndCaptureFact.setRawValue(
-      complexObject[_jsonV3HoverAndCaptureKey].toBool(false));
-  _refly90DegreesFact.setRawValue(
-      complexObject[_jsonV3Refly90DegreesKey].toBool(false));
-  _cameraTriggerInTurnAroundFact.setRawValue(
-      complexObject[_jsonV3CameraTriggerInTurnaroundKey].toBool(true));
-
-  _cameraCalc.valueSetIsDistance()->setRawValue(
-      complexObject[_jsonV3FixedValueIsAltitudeKey].toBool(true));
-  _cameraCalc.setDistanceToSurfaceRelative(
-      complexObject[_jsonV3GridAltitudeRelativeKey].toBool(true));
-
-  bool manualGrid = complexObject[_jsonV3ManualGridKey].toBool(true);
-
-  QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
-      {_jsonV3GridAltitudeKey, QJsonValue::Double, true},
-      {_jsonV3GridAltitudeRelativeKey, QJsonValue::Bool, true},
-      {_jsonV3GridAngleKey, QJsonValue::Double, true},
-      {_jsonV3GridSpacingKey, QJsonValue::Double, true},
-      {_jsonEntryPointKey, QJsonValue::Double, false},
-      {_jsonV3TurnaroundDistKey, QJsonValue::Double, true},
-  };
-  QJsonObject gridObject = complexObject[_jsonV3GridObjectKey].toObject();
-  if (!JsonHelper::validateKeys(gridObject, gridKeyInfoList, errorString)) {
     _ignoreRecalc = false;
-    return false;
-  }
-
-  _gridAngleFact.setRawValue(gridObject[_jsonV3GridAngleKey].toDouble());
-  _turnAroundDistanceFact.setRawValue(
-      gridObject[_jsonV3TurnaroundDistKey].toDouble());
-
-  if (gridObject.contains(_jsonEntryPointKey)) {
-    _entryPoint = gridObject[_jsonEntryPointKey].toInt();
-  } else {
-    _entryPoint = EntryLocationTopRight;
-  }
-
-  _cameraCalc.distanceToSurface()->setRawValue(
-      gridObject[_jsonV3GridAltitudeKey].toDouble());
-  _cameraCalc.adjustedFootprintSide()->setRawValue(
-      gridObject[_jsonV3GridSpacingKey].toDouble());
-  _cameraCalc.adjustedFootprintFrontal()->setRawValue(
-      complexObject[_jsonV3CameraTriggerDistanceKey].toDouble());
-
-  if (manualGrid) {
-    _cameraCalc.setCameraBrand(CameraCalc::canonicalManualCameraName());
-  } else {
-    if (!complexObject.contains(_jsonV3CameraObjectKey)) {
-      errorString = tr("%1 but %2 object is missing")
-                        .arg("manualGrid = false")
-                        .arg("camera");
-      _ignoreRecalc = false;
-      return false;
-    }
-
-    QJsonObject cameraObject = complexObject[_jsonV3CameraObjectKey].toObject();
-
-    // Older code had typo on "imageSideOverlap" incorrectly being
-    // "imageSizeOverlap"
-    QString incorrectImageSideOverlap = "imageSizeOverlap";
-    if (cameraObject.contains(incorrectImageSideOverlap)) {
-      cameraObject[_jsonV3SideOverlapKey] =
-          cameraObject[incorrectImageSideOverlap];
-      cameraObject.remove(incorrectImageSideOverlap);
-    }
-
-    QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
-        {_jsonV3GroundResolutionKey, QJsonValue::Double, true},
-        {_jsonV3FrontalOverlapKey, QJsonValue::Double, true},
-        {_jsonV3SideOverlapKey, QJsonValue::Double, true},
-        {_jsonV3CameraSensorWidthKey, QJsonValue::Double, true},
-        {_jsonV3CameraSensorHeightKey, QJsonValue::Double, true},
-        {_jsonV3CameraResolutionWidthKey, QJsonValue::Double, true},
-        {_jsonV3CameraResolutionHeightKey, QJsonValue::Double, true},
-        {_jsonV3CameraFocalLengthKey, QJsonValue::Double, true},
-        {_jsonV3CameraNameKey, QJsonValue::String, true},
-        {_jsonV3CameraOrientationLandscapeKey, QJsonValue::Bool, true},
-        {_jsonV3CameraMinTriggerIntervalKey, QJsonValue::Double, false},
+
+    return true;
+}
+
+bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
+{
+    QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
+        { VisualMissionItem::jsonTypeKey,               QJsonValue::String, true },
+        { ComplexMissionItem::jsonComplexItemTypeKey,   QJsonValue::String, true },
+        { QGCMapPolygon::jsonPolygonKey,                QJsonValue::Array,  true },
+        { _jsonV3GridObjectKey,                         QJsonValue::Object, true },
+        { _jsonV3CameraObjectKey,                       QJsonValue::Object, false },
+        { _jsonV3CameraTriggerDistanceKey,              QJsonValue::Double, true },
+        { _jsonV3ManualGridKey,                         QJsonValue::Bool,   true },
+        { _jsonV3FixedValueIsAltitudeKey,               QJsonValue::Bool,   true },
+        { _jsonV3HoverAndCaptureKey,                    QJsonValue::Bool,   false },
+        { _jsonV3Refly90DegreesKey,                     QJsonValue::Bool,   false },
+        { _jsonV3CameraTriggerInTurnaroundKey,          QJsonValue::Bool,   false },    // Should really be required, but it was missing from initial code due to bug
     };
-    if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList,
-                                  errorString)) {
-      _ignoreRecalc = false;
-      return false;
-    }
-
-    _cameraCalc.landscape()->setRawValue(
-        cameraObject[_jsonV3CameraOrientationLandscapeKey].toBool(true));
-    _cameraCalc.frontalOverlap()->setRawValue(
-        cameraObject[_jsonV3FrontalOverlapKey].toInt());
-    _cameraCalc.sideOverlap()->setRawValue(
-        cameraObject[_jsonV3SideOverlapKey].toInt());
-    _cameraCalc.sensorWidth()->setRawValue(
-        cameraObject[_jsonV3CameraSensorWidthKey].toDouble());
-    _cameraCalc.sensorHeight()->setRawValue(
-        cameraObject[_jsonV3CameraSensorHeightKey].toDouble());
-    _cameraCalc.focalLength()->setRawValue(
-        cameraObject[_jsonV3CameraFocalLengthKey].toDouble());
-    _cameraCalc.imageWidth()->setRawValue(
-        cameraObject[_jsonV3CameraResolutionWidthKey].toInt());
-    _cameraCalc.imageHeight()->setRawValue(
-        cameraObject[_jsonV3CameraResolutionHeightKey].toInt());
-    _cameraCalc.minTriggerInterval()->setRawValue(
-        cameraObject[_jsonV3CameraMinTriggerIntervalKey].toDouble(0));
-    _cameraCalc.imageDensity()->setRawValue(
-        cameraObject[_jsonV3GroundResolutionKey].toDouble());
-    _cameraCalc.fixedOrientation()->setRawValue(false);
-    _cameraCalc._setCameraNameFromV3TransectLoad(
-        cameraObject[_jsonV3CameraNameKey].toString());
-  }
-
-  // Polygon shape
-  /// Load a polygon from json
-  ///     @param json Json object to load from
-  ///     @param required true: no polygon in object will generate error
-  ///     @param errorString Error string if return is false
-  /// @return true: success, false: failure (errorString set)
-  if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */,
-                                       errorString)) {
-    _surveyAreaPolygon.clear();
-    _ignoreRecalc = false;
-    return false;
-  }
+    if (!JsonHelper::validateKeys(complexObject, mainKeyInfoList, errorString)) {
+        return false;
+    }
+
+    QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
+    QString complexType = complexObject[ComplexMissionItem::jsonComplexItemTypeKey].toString();
+    if (itemType != VisualMissionItem::jsonTypeComplexItemValue || complexType != jsonV3ComplexItemTypeValue) {
+        errorString = tr("%1 does not support loading this complex mission item type: %2:%3").arg(qgcApp()->applicationName()).arg(itemType).arg(complexType);
+        return false;
+    }
+
+    _ignoreRecalc = true;
+
+    setSequenceNumber(sequenceNumber);
+
+    _hoverAndCaptureFact.setRawValue            (complexObject[_jsonV3HoverAndCaptureKey].toBool(false));
+    _refly90DegreesFact.setRawValue             (complexObject[_jsonV3Refly90DegreesKey].toBool(false));
+    _cameraTriggerInTurnAroundFact.setRawValue  (complexObject[_jsonV3CameraTriggerInTurnaroundKey].toBool(true));
+
+    _cameraCalc.valueSetIsDistance()->setRawValue   (complexObject[_jsonV3FixedValueIsAltitudeKey].toBool(true));
+    _cameraCalc.setDistanceToSurfaceRelative        (complexObject[_jsonV3GridAltitudeRelativeKey].toBool(true));
+
+    bool manualGrid = complexObject[_jsonV3ManualGridKey].toBool(true);
+
+    QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
+        { _jsonV3GridAltitudeKey,           QJsonValue::Double, true },
+        { _jsonV3GridAltitudeRelativeKey,   QJsonValue::Bool,   true },
+        { _jsonV3GridAngleKey,              QJsonValue::Double, true },
+        { _jsonV3GridSpacingKey,            QJsonValue::Double, true },
+        { _jsonEntryPointKey,      QJsonValue::Double, false },
+        { _jsonV3TurnaroundDistKey,         QJsonValue::Double, true },
+    };
+    QJsonObject gridObject = complexObject[_jsonV3GridObjectKey].toObject();
+    if (!JsonHelper::validateKeys(gridObject, gridKeyInfoList, errorString)) {
+        _ignoreRecalc = false;
+        return false;
+    }
+
+    _gridAngleFact.setRawValue          (gridObject[_jsonV3GridAngleKey].toDouble());
+    _turnAroundDistanceFact.setRawValue (gridObject[_jsonV3TurnaroundDistKey].toDouble());
+
+    if (gridObject.contains(_jsonEntryPointKey)) {
+        _entryPoint = gridObject[_jsonEntryPointKey].toInt();
+    } else {
+        _entryPoint = EntryLocationTopRight;
+    }
+
+    _cameraCalc.distanceToSurface()->setRawValue        (gridObject[_jsonV3GridAltitudeKey].toDouble());
+    _cameraCalc.adjustedFootprintSide()->setRawValue    (gridObject[_jsonV3GridSpacingKey].toDouble());
+    _cameraCalc.adjustedFootprintFrontal()->setRawValue (complexObject[_jsonV3CameraTriggerDistanceKey].toDouble());
+
+    if (manualGrid) {
+        _cameraCalc.setCameraBrand(CameraCalc::canonicalManualCameraName());
+    } else {
+        if (!complexObject.contains(_jsonV3CameraObjectKey)) {
+            errorString = tr("%1 but %2 object is missing").arg("manualGrid = false").arg("camera");
+            _ignoreRecalc = false;
+            return false;
+        }
+
+        QJsonObject cameraObject = complexObject[_jsonV3CameraObjectKey].toObject();
+
+        // Older code had typo on "imageSideOverlap" incorrectly being "imageSizeOverlap"
+        QString incorrectImageSideOverlap = "imageSizeOverlap";
+        if (cameraObject.contains(incorrectImageSideOverlap)) {
+            cameraObject[_jsonV3SideOverlapKey] = cameraObject[incorrectImageSideOverlap];
+            cameraObject.remove(incorrectImageSideOverlap);
+        }
 
-  _ignoreRecalc = false;
+        QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
+            { _jsonV3GroundResolutionKey,           QJsonValue::Double, true },
+            { _jsonV3FrontalOverlapKey,             QJsonValue::Double, true },
+            { _jsonV3SideOverlapKey,                QJsonValue::Double, true },
+            { _jsonV3CameraSensorWidthKey,          QJsonValue::Double, true },
+            { _jsonV3CameraSensorHeightKey,         QJsonValue::Double, true },
+            { _jsonV3CameraResolutionWidthKey,      QJsonValue::Double, true },
+            { _jsonV3CameraResolutionHeightKey,     QJsonValue::Double, true },
+            { _jsonV3CameraFocalLengthKey,          QJsonValue::Double, true },
+            { _jsonV3CameraNameKey,                 QJsonValue::String, true },
+            { _jsonV3CameraOrientationLandscapeKey, QJsonValue::Bool,   true },
+            { _jsonV3CameraMinTriggerIntervalKey,   QJsonValue::Double, false },
+        };
+        if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList, errorString)) {
+            _ignoreRecalc = false;
+            return false;
+        }
+
+        _cameraCalc.landscape()->setRawValue            (cameraObject[_jsonV3CameraOrientationLandscapeKey].toBool(true));
+        _cameraCalc.frontalOverlap()->setRawValue       (cameraObject[_jsonV3FrontalOverlapKey].toInt());
+        _cameraCalc.sideOverlap()->setRawValue          (cameraObject[_jsonV3SideOverlapKey].toInt());
+        _cameraCalc.sensorWidth()->setRawValue          (cameraObject[_jsonV3CameraSensorWidthKey].toDouble());
+        _cameraCalc.sensorHeight()->setRawValue         (cameraObject[_jsonV3CameraSensorHeightKey].toDouble());
+        _cameraCalc.focalLength()->setRawValue          (cameraObject[_jsonV3CameraFocalLengthKey].toDouble());
+        _cameraCalc.imageWidth()->setRawValue           (cameraObject[_jsonV3CameraResolutionWidthKey].toInt());
+        _cameraCalc.imageHeight()->setRawValue          (cameraObject[_jsonV3CameraResolutionHeightKey].toInt());
+        _cameraCalc.minTriggerInterval()->setRawValue   (cameraObject[_jsonV3CameraMinTriggerIntervalKey].toDouble(0));
+        _cameraCalc.imageDensity()->setRawValue         (cameraObject[_jsonV3GroundResolutionKey].toDouble());
+        _cameraCalc.fixedOrientation()->setRawValue     (false);
+        _cameraCalc._setCameraNameFromV3TransectLoad    (cameraObject[_jsonV3CameraNameKey].toString());
+    }
+
+    // Polygon shape
+    /// Load a polygon from json
+    ///     @param json Json object to load from
+    ///     @param required true: no polygon in object will generate error
+    ///     @param errorString Error string if return is false
+    /// @return true: success, false: failure (errorString set)
+    if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */, errorString)) {
+        _surveyAreaPolygon.clear();
+        _ignoreRecalc = false;
+        return false;
+    }
+
+    _ignoreRecalc = false;
 
-  return true;
+    return true;
 }
 
-/// Reverse the order of the transects. First transect becomes last and so
-/// forth.
-void SurveyComplexItem::_reverseTransectOrder(
-    QList<QList<QGeoCoordinate>> &transects) {
-  QList<QList<QGeoCoordinate>> rgReversedTransects;
-  for (int i = transects.count() - 1; i >= 0; i--) {
-    rgReversedTransects.append(transects[i]);
-  }
-  transects = rgReversedTransects;
+/// Reverse the order of the transects. First transect becomes last and so forth.
+void SurveyComplexItem::_reverseTransectOrder(QList<QList<QGeoCoordinate>>& transects)
+{
+    QList<QList<QGeoCoordinate>> rgReversedTransects;
+    for (int i=transects.count() - 1; i>=0; i--) {
+        rgReversedTransects.append(transects[i]);
+    }
+    transects = rgReversedTransects;
 }
 
-/// Reverse the order of all points withing each transect, First point becomes
-/// last and so forth.
-void SurveyComplexItem::_reverseInternalTransectPoints(
-    QList<QList<QGeoCoordinate>> &transects) {
-  for (int i = 0; i < transects.count(); i++) {
-    QList<QGeoCoordinate> rgReversedCoords;
-    QList<QGeoCoordinate> &rgOriginalCoords = transects[i];
-    for (int j = rgOriginalCoords.count() - 1; j >= 0; j--) {
-      rgReversedCoords.append(rgOriginalCoords[j]);
-    }
-    transects[i] = rgReversedCoords;
-  }
+/// Reverse the order of all points withing each transect, First point becomes last and so forth.
+void SurveyComplexItem::_reverseInternalTransectPoints(QList<QList<QGeoCoordinate>>& transects)
+{
+    for (int i=0; i<transects.count(); i++) {
+        QList<QGeoCoordinate> rgReversedCoords;
+        QList<QGeoCoordinate>& rgOriginalCoords = transects[i];
+        for (int j=rgOriginalCoords.count()-1; j>=0; j--) {
+            rgReversedCoords.append(rgOriginalCoords[j]);
+        }
+        transects[i] = rgReversedCoords;
+    }
 }
 
-/// Reorders the transects such that the first transect is the shortest distance
-/// to the specified coordinate and the first point within that transect is the
-/// shortest distance to the specified coordinate.
+/// Reorders the transects such that the first transect is the shortest distance to the specified coordinate
+/// and the first point within that transect is the shortest distance to the specified coordinate.
 ///     @param distanceCoord Coordinate to measure distance against
 ///     @param transects Transects to test and reorder
-void SurveyComplexItem::_optimizeTransectsForShortestDistance(
-    const QGeoCoordinate &distanceCoord,
-    QList<QList<QGeoCoordinate>> &transects) {
-  double rgTransectDistance[4];
-  rgTransectDistance[0] = transects.first().first().distanceTo(distanceCoord);
-  rgTransectDistance[1] = transects.first().last().distanceTo(distanceCoord);
-  rgTransectDistance[2] = transects.last().first().distanceTo(distanceCoord);
-  rgTransectDistance[3] = transects.last().last().distanceTo(distanceCoord);
-
-  int shortestIndex = 0;
-  double shortestDistance = rgTransectDistance[0];
-  for (int i = 1; i < 3; i++) {
-    if (rgTransectDistance[i] < shortestDistance) {
-      shortestIndex = i;
-      shortestDistance = rgTransectDistance[i];
-    }
-  }
-
-  if (shortestIndex > 1) {
-    // We need to reverse the order of segments
-    _reverseTransectOrder(transects);
-  }
-  if (shortestIndex & 1) {
-    // We need to reverse the points within each segment
-    _reverseInternalTransectPoints(transects);
-  }
+void SurveyComplexItem::_optimizeTransectsForShortestDistance(const QGeoCoordinate& distanceCoord, QList<QList<QGeoCoordinate>>& transects)
+{
+    double rgTransectDistance[4];
+    rgTransectDistance[0] = transects.first().first().distanceTo(distanceCoord);
+    rgTransectDistance[1] = transects.first().last().distanceTo(distanceCoord);
+    rgTransectDistance[2] = transects.last().first().distanceTo(distanceCoord);
+    rgTransectDistance[3] = transects.last().last().distanceTo(distanceCoord);
+
+    int shortestIndex = 0;
+    double shortestDistance = rgTransectDistance[0];
+    for (int i=1; i<3; i++) {
+        if (rgTransectDistance[i] < shortestDistance) {
+            shortestIndex = i;
+            shortestDistance = rgTransectDistance[i];
+        }
+    }
+
+    if (shortestIndex > 1) {
+        // We need to reverse the order of segments
+        _reverseTransectOrder(transects);
+    }
+    if (shortestIndex & 1) {
+        // We need to reverse the points within each segment
+        _reverseInternalTransectPoints(transects);
+    }
 }
 
-qreal SurveyComplexItem::_ccw(QPointF pt1, QPointF pt2, QPointF pt3) {
-  return (pt2.x() - pt1.x()) * (pt3.y() - pt1.y()) -
-         (pt2.y() - pt1.y()) * (pt3.x() - pt1.x());
+qreal SurveyComplexItem::_ccw(QPointF pt1, QPointF pt2, QPointF pt3)
+{
+    return (pt2.x()-pt1.x())*(pt3.y()-pt1.y()) - (pt2.y()-pt1.y())*(pt3.x()-pt1.x());
 }
 
-qreal SurveyComplexItem::_dp(QPointF pt1, QPointF pt2) {
-  return (pt2.x() - pt1.x()) / qSqrt((pt2.x() - pt1.x()) * (pt2.x() - pt1.x()) +
-                                     (pt2.y() - pt1.y()) * (pt2.y() - pt1.y()));
+qreal SurveyComplexItem::_dp(QPointF pt1, QPointF pt2)
+{
+    return (pt2.x()-pt1.x())/qSqrt((pt2.x()-pt1.x())*(pt2.x()-pt1.x()) + (pt2.y()-pt1.y())*(pt2.y()-pt1.y()));
 }
 
-void SurveyComplexItem::_swapPoints(QList<QPointF> &points, int index1,
-                                    int index2) {
-  QPointF temp = points[index1];
-  points[index1] = points[index2];
-  points[index2] = temp;
+void SurveyComplexItem::_swapPoints(QList<QPointF>& points, int index1, int index2)
+{
+    QPointF temp = points[index1];
+    points[index1] = points[index2];
+    points[index2] = temp;
 }
 
-/// Returns true if the current grid angle generates north/south oriented
-/// transects
-bool SurveyComplexItem::_gridAngleIsNorthSouthTransects() {
-  // Grid angle ranges from -360<->360
-  double gridAngle = qAbs(_gridAngleFact.rawValue().toDouble());
-  return gridAngle < 45.0 || (gridAngle > 360.0 - 45.0) ||
-         (gridAngle > 90.0 + 45.0 && gridAngle < 270.0 - 45.0);
+/// Returns true if the current grid angle generates north/south oriented transects
+bool SurveyComplexItem::_gridAngleIsNorthSouthTransects()
+{
+    // Grid angle ranges from -360<->360
+    double gridAngle = qAbs(_gridAngleFact.rawValue().toDouble());
+    return gridAngle < 45.0 || (gridAngle > 360.0 - 45.0) || (gridAngle > 90.0 + 45.0 && gridAngle < 270.0 - 45.0);
 }
 
-void SurveyComplexItem::_adjustTransectsToEntryPointLocation(
-    QList<QList<QGeoCoordinate>> &transects) {
-  if (transects.count() == 0) {
-    return;
-  }
-
-  bool reversePoints = false;
-  bool reverseTransects = false;
-
-  if (_entryPoint == EntryLocationBottomLeft ||
-      _entryPoint == EntryLocationBottomRight) {
-    reversePoints = true;
-  }
-  if (_entryPoint == EntryLocationTopRight ||
-      _entryPoint == EntryLocationBottomRight) {
-    reverseTransects = true;
-  }
-
-  if (reversePoints) {
-    qCDebug(SurveyComplexItemLog)
-        << "_adjustTransectsToEntryPointLocation Reverse Points";
-    _reverseInternalTransectPoints(transects);
-  }
-  if (reverseTransects) {
-    qCDebug(SurveyComplexItemLog)
-        << "_adjustTransectsToEntryPointLocation Reverse Transects";
-    _reverseTransectOrder(transects);
-  }
-
-  qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation "
-                                   "Modified entry point:entryLocation"
-                                << transects.first().first() << _entryPoint;
+void SurveyComplexItem::_adjustTransectsToEntryPointLocation(QList<QList<QGeoCoordinate>>& transects)
+{
+    if (transects.count() == 0) {
+        return;
+    }
+
+    bool reversePoints = false;
+    bool reverseTransects = false;
+
+    if (_entryPoint == EntryLocationBottomLeft || _entryPoint == EntryLocationBottomRight) {
+        reversePoints = true;
+    }
+    if (_entryPoint == EntryLocationTopRight || _entryPoint == EntryLocationBottomRight) {
+        reverseTransects = true;
+    }
+
+    if (reversePoints) {
+        qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation Reverse Points";
+        _reverseInternalTransectPoints(transects);
+    }
+    if (reverseTransects) {
+        qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation Reverse Transects";
+        _reverseTransectOrder(transects);
+    }
+
+    qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation Modified entry point:entryLocation" << transects.first().first() << _entryPoint;
 }
 
-QPointF SurveyComplexItem::_rotatePoint(const QPointF &point,
-                                        const QPointF &origin, double angle) {
-  QPointF rotated;
-  double radians = (M_PI / 180.0) * -angle;
+QPointF SurveyComplexItem::_rotatePoint(const QPointF& point, const QPointF& origin, double angle)
+{
+    QPointF rotated;
+    double radians = (M_PI / 180.0) * -angle;
 
-  rotated.setX(((point.x() - origin.x()) * cos(radians)) -
-               ((point.y() - origin.y()) * sin(radians)) + origin.x());
-  rotated.setY(((point.x() - origin.x()) * sin(radians)) +
-               ((point.y() - origin.y()) * cos(radians)) + origin.y());
+    rotated.setX(((point.x() - origin.x()) * cos(radians)) - ((point.y() - origin.y()) * sin(radians)) + origin.x());
+    rotated.setY(((point.x() - origin.x()) * sin(radians)) + ((point.y() - origin.y()) * cos(radians)) + origin.y());
 
-  return rotated;
+    return rotated;
 }
 
-void SurveyComplexItem::_intersectLinesWithRect(const QList<QLineF> &lineList,
-                                                const QRectF &boundRect,
-                                                QList<QLineF> &resultLines) {
-  QLineF topLine(boundRect.topLeft(), boundRect.topRight());
-  QLineF bottomLine(boundRect.bottomLeft(), boundRect.bottomRight());
-  QLineF leftLine(boundRect.topLeft(), boundRect.bottomLeft());
-  QLineF rightLine(boundRect.topRight(), boundRect.bottomRight());
-
-  for (int i = 0; i < lineList.count(); i++) {
-    QPointF intersectPoint;
-    QLineF intersectLine;
-    const QLineF &line = lineList[i];
-
-    auto isLineBoundedIntersect =
-        [&line, &intersectPoint](const QLineF &linePosition) {
+void SurveyComplexItem::_intersectLinesWithRect(const QList<QLineF>& lineList, const QRectF& boundRect, QList<QLineF>& resultLines)
+{
+    QLineF topLine      (boundRect.topLeft(),       boundRect.topRight());
+    QLineF bottomLine   (boundRect.bottomLeft(),    boundRect.bottomRight());
+    QLineF leftLine     (boundRect.topLeft(),       boundRect.bottomLeft());
+    QLineF rightLine    (boundRect.topRight(),      boundRect.bottomRight());
+
+    for (int i=0; i<lineList.count(); i++) {
+        QPointF intersectPoint;
+        QLineF intersectLine;
+        const QLineF& line = lineList[i];
+
+        auto isLineBoundedIntersect = [&line, &intersectPoint](const QLineF& linePosition) {
 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
-          return line.intersect(linePosition, &intersectPoint) ==
-                 QLineF::BoundedIntersection;
+            return line.intersect(linePosition, &intersectPoint) == QLineF::BoundedIntersection;
 #else
-          return line.intersects(linePosition, &intersectPoint) ==
-                 QLineF::BoundedIntersection;
+            return line.intersects(linePosition, &intersectPoint) == QLineF::BoundedIntersection;
 #endif
         };
 
-    int foundCount = 0;
-    if (isLineBoundedIntersect(topLine)) {
-      intersectLine.setP1(intersectPoint);
-      foundCount++;
-    }
-    if (isLineBoundedIntersect(rightLine)) {
-      if (foundCount == 0) {
-        intersectLine.setP1(intersectPoint);
-      } else {
-        if (foundCount != 1) {
-          qWarning() << "Found more than two intersecting points";
+        int foundCount = 0;
+        if (isLineBoundedIntersect(topLine)) {
+            intersectLine.setP1(intersectPoint);
+            foundCount++;
         }
-        intersectLine.setP2(intersectPoint);
-      }
-      foundCount++;
-    }
-    if (isLineBoundedIntersect(bottomLine)) {
-      if (foundCount == 0) {
-        intersectLine.setP1(intersectPoint);
-      } else {
-        if (foundCount != 1) {
-          qWarning() << "Found more than two intersecting points";
+        if (isLineBoundedIntersect(rightLine)) {
+            if (foundCount == 0) {
+                intersectLine.setP1(intersectPoint);
+            } else {
+                if (foundCount != 1) {
+                    qWarning() << "Found more than two intersecting points";
+                }
+                intersectLine.setP2(intersectPoint);
+            }
+            foundCount++;
         }
-        intersectLine.setP2(intersectPoint);
-      }
-      foundCount++;
-    }
-    if (isLineBoundedIntersect(leftLine)) {
-      if (foundCount == 0) {
-        intersectLine.setP1(intersectPoint);
-      } else {
-        if (foundCount != 1) {
-          qWarning() << "Found more than two intersecting points";
+        if (isLineBoundedIntersect(bottomLine)) {
+            if (foundCount == 0) {
+                intersectLine.setP1(intersectPoint);
+            } else {
+                if (foundCount != 1) {
+                    qWarning() << "Found more than two intersecting points";
+                }
+                intersectLine.setP2(intersectPoint);
+            }
+            foundCount++;
+        }
+        if (isLineBoundedIntersect(leftLine)) {
+            if (foundCount == 0) {
+                intersectLine.setP1(intersectPoint);
+            } else {
+                if (foundCount != 1) {
+                    qWarning() << "Found more than two intersecting points";
+                }
+                intersectLine.setP2(intersectPoint);
+            }
+            foundCount++;
         }
-        intersectLine.setP2(intersectPoint);
-      }
-      foundCount++;
-    }
 
-    if (foundCount == 2) {
-      resultLines += intersectLine;
+        if (foundCount == 2) {
+            resultLines += intersectLine;
+        }
     }
-  }
 }
 
-void SurveyComplexItem::_intersectLinesWithPolygon(
-    const QList<QLineF> &lineList, const QPolygonF &polygon,
-    QList<QLineF> &resultLines) {
-  resultLines.clear();
+void SurveyComplexItem::_intersectLinesWithPolygon(const QList<QLineF>& lineList, const QPolygonF& polygon, QList<QLineF>& resultLines)
+{
+    resultLines.clear();
 
-  for (int i = 0; i < lineList.count(); i++) {
-    const QLineF &line = lineList[i];
-    QList<QPointF> intersections;
+    for (int i=0; i<lineList.count(); i++) {
+        const QLineF& line = lineList[i];
+        QList<QPointF> intersections;
 
-    // Intersect the line with all the polygon edges
-    for (int j = 0; j < polygon.count() - 1; j++) {
-      QPointF intersectPoint;
-      QLineF polygonLine = QLineF(polygon[j], polygon[j + 1]);
+        // Intersect the line with all the polygon edges
+        for (int j=0; j<polygon.count()-1; j++) {
+            QPointF intersectPoint;
+            QLineF polygonLine = QLineF(polygon[j], polygon[j+1]);
 
 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
-      auto intersect = line.intersect(polygonLine, &intersectPoint);
+            auto intersect = line.intersect(polygonLine, &intersectPoint);
 #else
-      auto intersect = line.intersects(polygonLine, &intersectPoint);
+            auto intersect = line.intersects(polygonLine, &intersectPoint);
 #endif
-      if (intersect == QLineF::BoundedIntersection) {
-        if (!intersections.contains(intersectPoint)) {
-          intersections.append(intersectPoint);
-        }
-      }
-    }
-
-    // We now have one or more intersection points all along the same line. Find
-    // the two which are furthest away from each other to form the transect.
-    if (intersections.count() > 1) {
-      QPointF firstPoint;
-      QPointF secondPoint;
-      double currentMaxDistance = 0;
-
-      for (int i = 0; i < intersections.count(); i++) {
-        for (int j = 0; j < intersections.count(); j++) {
-          QLineF lineTest(intersections[i], intersections[j]);
-
-          double newMaxDistance = lineTest.length();
-          if (newMaxDistance > currentMaxDistance) {
-            firstPoint = intersections[i];
-            secondPoint = intersections[j];
-            currentMaxDistance = newMaxDistance;
-          }
+            if (intersect == QLineF::BoundedIntersection) {
+                if (!intersections.contains(intersectPoint)) {
+                    intersections.append(intersectPoint);
+                }
+            }
         }
-      }
 
-      resultLines += QLineF(firstPoint, secondPoint);
+        // We now have one or more intersection points all along the same line. Find the two
+        // which are furthest away from each other to form the transect.
+        if (intersections.count() > 1) {
+            QPointF firstPoint;
+            QPointF secondPoint;
+            double currentMaxDistance = 0;
+
+            for (int i=0; i<intersections.count(); i++) {
+                for (int j=0; j<intersections.count(); j++) {
+                    QLineF lineTest(intersections[i], intersections[j]);
+                    \
+                    double newMaxDistance = lineTest.length();
+                    if (newMaxDistance > currentMaxDistance) {
+                        firstPoint = intersections[i];
+                        secondPoint = intersections[j];
+                        currentMaxDistance = newMaxDistance;
+                    }
+                }
+            }
+
+            resultLines += QLineF(firstPoint, secondPoint);
+        }
     }
-  }
 }
 
-/// Adjust the line segments such that they are all going the same direction
-/// with respect to going from P1->P2
-void SurveyComplexItem::_adjustLineDirection(const QList<QLineF> &lineList,
-                                             QList<QLineF> &resultLines) {
-  qreal firstAngle = 0;
-  for (int i = 0; i < lineList.count(); i++) {
-    const QLineF &line = lineList[i];
-    QLineF adjustedLine;
+/// Adjust the line segments such that they are all going the same direction with respect to going from P1->P2
+void SurveyComplexItem::_adjustLineDirection(const QList<QLineF>& lineList, QList<QLineF>& resultLines)
+{
+    qreal firstAngle = 0;
+    for (int i=0; i<lineList.count(); i++) {
+        const QLineF& line = lineList[i];
+        QLineF adjustedLine;
 
-    if (i == 0) {
-      firstAngle = line.angle();
-    }
+        if (i == 0) {
+            firstAngle = line.angle();
+        }
 
-    if (qAbs(line.angle() - firstAngle) > 1.0) {
-      adjustedLine.setP1(line.p2());
-      adjustedLine.setP2(line.p1());
-    } else {
-      adjustedLine = line;
-    }
+        if (qAbs(line.angle() - firstAngle) > 1.0) {
+            adjustedLine.setP1(line.p2());
+            adjustedLine.setP2(line.p1());
+        } else {
+            adjustedLine = line;
+        }
 
-    resultLines += adjustedLine;
-  }
+        resultLines += adjustedLine;
+    }
 }
 
-double SurveyComplexItem::_clampGridAngle90(double gridAngle) {
-  // Clamp grid angle to -90<->90. This prevents transects from being rotated to
-  // a reversed order.
-  if (gridAngle > 90.0) {
-    gridAngle -= 180.0;
-  } else if (gridAngle < -90.0) {
-    gridAngle += 180;
-  }
-  return gridAngle;
+double SurveyComplexItem::_clampGridAngle90(double gridAngle)
+{
+    // Clamp grid angle to -90<->90. This prevents transects from being rotated to a reversed order.
+    if (gridAngle > 90.0) {
+        gridAngle -= 180.0;
+    } else if (gridAngle < -90.0) {
+        gridAngle += 180;
+    }
+    return gridAngle;
 }
 
-bool SurveyComplexItem::_nextTransectCoord(
-    const QList<QGeoCoordinate> &transectPoints, int pointIndex,
-    QGeoCoordinate &coord) {
-  if (pointIndex > transectPoints.count()) {
-    qWarning() << "Bad grid generation";
-    return false;
-  }
+bool SurveyComplexItem::_nextTransectCoord(const QList<QGeoCoordinate>& transectPoints, int pointIndex, QGeoCoordinate& coord)
+{
+    if (pointIndex > transectPoints.count()) {
+        qWarning() << "Bad grid generation";
+        return false;
+    }
 
-  coord = transectPoints[pointIndex];
-  return true;
+    coord = transectPoints[pointIndex];
+    return true;
 }
 
-bool SurveyComplexItem::_hasTurnaround(void) const {
-  return _turnAroundDistance() > 0;
+bool SurveyComplexItem::_hasTurnaround(void) const
+{
+    return _turnAroundDistance() > 0;
 }
 
-double SurveyComplexItem::_turnaroundDistance(void) const {
-  return _turnAroundDistanceFact.rawValue().toDouble();
+double SurveyComplexItem::_turnaroundDistance(void) const
+{
+    return _turnAroundDistanceFact.rawValue().toDouble();
 }
 
-void SurveyComplexItem::_rebuildTransectsPhase1(void) {
-  bool split = splitConcavePolygons()->rawValue().toBool();
-  if (split) {
-    _rebuildTransectsPhase1WorkerSplitPolygons(false /* refly */);
-  } else {
-    _rebuildTransectsPhase1WorkerSinglePolygon(false /* refly */);
-  }
-  if (_refly90DegreesFact.rawValue().toBool()) {
-    if (split) {
-      _rebuildTransectsPhase1WorkerSplitPolygons(true /* refly */);
-    } else {
-      _rebuildTransectsPhase1WorkerSinglePolygon(true /* refly */);
+void SurveyComplexItem::_rebuildTransectsPhase1(void)
+{
+    bool split = splitConcavePolygons()->rawValue().toBool();
+	if (split) {
+		_rebuildTransectsPhase1WorkerSplitPolygons(false /* refly */);
+	} else {
+		_rebuildTransectsPhase1WorkerSinglePolygon(false /* refly */);
+	}
+    if (_refly90DegreesFact.rawValue().toBool()) {
+    	if (split) {
+    		_rebuildTransectsPhase1WorkerSplitPolygons(true /* refly */);
+    	} else {
+    		_rebuildTransectsPhase1WorkerSinglePolygon(true /* refly */);
+    	}
     }
-  }
 }
 
-void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly) {
-  if (_ignoreRecalc) {
-    return;
-  }
-
-  // If the transects are getting rebuilt then any previously loaded mission
-  // items are now invalid
-  if (_loadedMissionItemsParent) {
-    _loadedMissionItems.clear();
-    _loadedMissionItemsParent->deleteLater();
-    _loadedMissionItemsParent = nullptr;
-  }
-
-  // First pass will clear old transect data, refly will append to existing data
-  if (!refly) {
-    _transects.clear();
-    _transectsPathHeightInfo.clear();
-  }
-
-  if (_surveyAreaPolygon.count() < 3) {
-    return;
-  }
-
-  // Convert polygon to NED
-
-  QList<QPointF> polygonPoints;
-  QGeoCoordinate tangentOrigin = _surveyAreaPolygon.pathModel()
-                                     .value<QGCQGeoCoordinate *>(0)
-                                     ->coordinate();
-  qCDebug(SurveyComplexItemLog)
-      << "_rebuildTransectsPhase1 Convert polygon to NED - "
-         "_surveyAreaPolygon.count():tangentOrigin"
-      << _surveyAreaPolygon.count() << tangentOrigin;
-  for (int i = 0; i < _surveyAreaPolygon.count(); i++) {
-    double y, x, down;
-    QGeoCoordinate vertex = _surveyAreaPolygon.pathModel()
-                                .value<QGCQGeoCoordinate *>(i)
-                                ->coordinate();
-    if (i == 0) {
-      // This avoids a nan calculation that comes out of convertGeoToNed
-      x = y = 0;
-    } else {
-      convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
-    }
-    polygonPoints += QPointF(x, y);
-    qCDebug(SurveyComplexItemLog)
-        << "_rebuildTransectsPhase1 vertex:x:y" << vertex
-        << polygonPoints.last().x() << polygonPoints.last().y();
-  }
-
-  // Generate transects
-
-  double gridAngle = _gridAngleFact.rawValue().toDouble();
-  double gridSpacing =
-      _cameraCalc.adjustedFootprintSide()->rawValue().toDouble();
-  if (gridSpacing < 0.5) {
-    // We can't let gridSpacing get too small otherwise we will end up with too
-    // many transects. So we limit to 0.5 meter spacing as min and set to huge
-    // value which will cause a single transect to be added.
-    gridSpacing = 100000;
-  }
-
-  gridAngle = _clampGridAngle90(gridAngle);
-  gridAngle += refly ? 90 : 0;
-  qCDebug(SurveyComplexItemLog)
-      << "_rebuildTransectsPhase1 Clamped grid angle" << gridAngle;
-
-  qCDebug(SurveyComplexItemLog)
-      << "_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing
-      << gridAngle << refly;
-
-  // Convert polygon to bounding rect
-
-  qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Polygon";
-  QPolygonF polygon;
-  for (int i = 0; i < polygonPoints.count(); i++) {
-    qCDebug(SurveyComplexItemLog) << "Vertex" << polygonPoints[i];
-    polygon << polygonPoints[i];
-  }
-  polygon << polygonPoints[0];
-  QRectF boundingRect = polygon.boundingRect();
-  QPointF boundingCenter = boundingRect.center();
-  qCDebug(SurveyComplexItemLog)
-      << "Bounding rect" << boundingRect.topLeft().x()
-      << boundingRect.topLeft().y() << boundingRect.bottomRight().x()
-      << boundingRect.bottomRight().y();
-
-  // Create set of rotated parallel lines within the expanded bounding rect.
-  // Make the lines larger than the bounding box to guarantee intersection.
-
-  QList<QLineF> lineList;
-
-  // Transects are generated to be as long as the largest width/height of the
-  // bounding rect plus some fudge factor. This way they will always be
-  // guaranteed to intersect with a polygon edge no matter what angle they are
-  // rotated to. They are initially generated with the transects flowing from
-  // west to east and then points within the transect north to south.
-  double maxWidth = qMax(boundingRect.width(), boundingRect.height()) + 2000.0;
-  double halfWidth = maxWidth / 2.0;
-  double transectX = boundingCenter.x() - halfWidth;
-  double transectXMax = transectX + maxWidth;
-  while (transectX < transectXMax) {
-    double transectYTop = boundingCenter.y() - halfWidth;
-    double transectYBottom = boundingCenter.y() + halfWidth;
-
-    lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop),
-                                    boundingCenter, gridAngle),
-                       _rotatePoint(QPointF(transectX, transectYBottom),
-                                    boundingCenter, gridAngle));
-    transectX += gridSpacing;
-  }
-
-  // Now intersect the lines with the polygon
-  QList<QLineF> intersectLines;
+void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
+{
+    if (_ignoreRecalc) {
+        return;
+    }
+
+    // If the transects are getting rebuilt then any previously loaded mission items are now invalid
+    if (_loadedMissionItemsParent) {
+        _loadedMissionItems.clear();
+        _loadedMissionItemsParent->deleteLater();
+        _loadedMissionItemsParent = nullptr;
+    }
+
+    // First pass will clear old transect data, refly will append to existing data
+    if (!refly) {
+        _transects.clear();
+        _transectsPathHeightInfo.clear();
+    }
+
+    if (_surveyAreaPolygon.count() < 3) {
+        return;
+    }
+
+    // Convert polygon to NED
+
+    QList<QPointF> polygonPoints;
+    QGeoCoordinate tangentOrigin = _surveyAreaPolygon.pathModel().value<QGCQGeoCoordinate*>(0)->coordinate();
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Convert polygon to NED - _surveyAreaPolygon.count():tangentOrigin" << _surveyAreaPolygon.count() << tangentOrigin;
+    for (int i=0; i<_surveyAreaPolygon.count(); i++) {
+        double y, x, down;
+        QGeoCoordinate vertex = _surveyAreaPolygon.pathModel().value<QGCQGeoCoordinate*>(i)->coordinate();
+        if (i == 0) {
+            // This avoids a nan calculation that comes out of convertGeoToNed
+            x = y = 0;
+        } else {
+            convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
+        }
+        polygonPoints += QPointF(x, y);
+        qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 vertex:x:y" << vertex << polygonPoints.last().x() << polygonPoints.last().y();
+    }
+
+    // Generate transects
+
+    double gridAngle = _gridAngleFact.rawValue().toDouble();
+    double gridSpacing = _cameraCalc.adjustedFootprintSide()->rawValue().toDouble();
+    if (gridSpacing < 0.5) {
+        // We can't let gridSpacing get too small otherwise we will end up with too many transects.
+        // So we limit to 0.5 meter spacing as min and set to huge value which will cause a single
+        // transect to be added.
+        gridSpacing = 100000;
+    }
+
+    gridAngle = _clampGridAngle90(gridAngle);
+    gridAngle += refly ? 90 : 0;
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Clamped grid angle" << gridAngle;
+
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing << gridAngle << refly;
+
+    // Convert polygon to bounding rect
+
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Polygon";
+    QPolygonF polygon;
+    for (int i=0; i<polygonPoints.count(); i++) {
+        qCDebug(SurveyComplexItemLog) << "Vertex" << polygonPoints[i];
+        polygon << polygonPoints[i];
+    }
+    polygon << polygonPoints[0];
+    QRectF boundingRect = polygon.boundingRect();
+    QPointF boundingCenter = boundingRect.center();
+    qCDebug(SurveyComplexItemLog) << "Bounding rect" << boundingRect.topLeft().x() << boundingRect.topLeft().y() << boundingRect.bottomRight().x() << boundingRect.bottomRight().y();
+
+    // Create set of rotated parallel lines within the expanded bounding rect. Make the lines larger than the
+    // bounding box to guarantee intersection.
+
+    QList<QLineF> lineList;
+
+    // Transects are generated to be as long as the largest width/height of the bounding rect plus some fudge factor.
+    // This way they will always be guaranteed to intersect with a polygon edge no matter what angle they are rotated to.
+    // They are initially generated with the transects flowing from west to east and then points within the transect north to south.
+    double maxWidth = qMax(boundingRect.width(), boundingRect.height()) + 2000.0;
+    double halfWidth = maxWidth / 2.0;
+    double transectX = boundingCenter.x() - halfWidth;
+    double transectXMax = transectX + maxWidth;
+    while (transectX < transectXMax) {
+        double transectYTop = boundingCenter.y() - halfWidth;
+        double transectYBottom = boundingCenter.y() + halfWidth;
+
+        lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop), boundingCenter, gridAngle), _rotatePoint(QPointF(transectX, transectYBottom), boundingCenter, gridAngle));
+        transectX += gridSpacing;
+    }
+
+    // Now intersect the lines with the polygon
+    QList<QLineF> intersectLines;
 #if 1
-  _intersectLinesWithPolygon(lineList, polygon, intersectLines);
+    _intersectLinesWithPolygon(lineList, polygon, intersectLines);
 #else
-  // This is handy for debugging grid problems, not for release
-  intersectLines = lineList;
+    // This is handy for debugging grid problems, not for release
+    intersectLines = lineList;
 #endif
 
-  // Less than two transects intersected with the polygon:
-  //      Create a single transect which goes through the center of the polygon
-  //      Intersect it with the polygon
-  if (intersectLines.count() < 2) {
-    _surveyAreaPolygon.center();
-    QLineF firstLine = lineList.first();
-    QPointF lineCenter = firstLine.pointAt(0.5);
-    QPointF centerOffset = boundingCenter - lineCenter;
-    firstLine.translate(centerOffset);
-    lineList.clear();
-    lineList.append(firstLine);
-    intersectLines = lineList;
-    _intersectLinesWithPolygon(lineList, polygon, intersectLines);
-  }
-
-  // Make sure all lines are going the same direction. Polygon intersection
-  // leads to lines which can be in varied directions depending on the order of
-  // the intesecting sides.
-  QList<QLineF> resultLines;
-  _adjustLineDirection(intersectLines, resultLines);
-
-  // Convert from NED to Geo
-  QList<QList<QGeoCoordinate>> transects;
-  for (const QLineF &line : resultLines) {
-    QGeoCoordinate coord;
-    QList<QGeoCoordinate> transect;
-
-    convertNedToGeo(line.p1().y(), line.p1().x(), 0, tangentOrigin, &coord);
-    transect.append(coord);
-    convertNedToGeo(line.p2().y(), line.p2().x(), 0, tangentOrigin, &coord);
-    transect.append(coord);
-
-    transects.append(transect);
-  }
-
-  _adjustTransectsToEntryPointLocation(transects);
-
-  if (refly) {
-    _optimizeTransectsForShortestDistance(_transects.last().last().coord,
-                                          transects);
-  }
-
-  if (_flyAlternateTransectsFact.rawValue().toBool()) {
-    QList<QList<QGeoCoordinate>> alternatingTransects;
-    for (int i = 0; i < transects.count(); i++) {
-      if (!(i & 1)) {
-        alternatingTransects.append(transects[i]);
-      }
-    }
-    for (int i = transects.count() - 1; i > 0; i--) {
-      if (i & 1) {
-        alternatingTransects.append(transects[i]);
-      }
-    }
-    transects = alternatingTransects;
-  }
-
-  // Adjust to lawnmower pattern
-  bool reverseVertices = false;
-  for (int i = 0; i < transects.count(); i++) {
-    // We must reverse the vertices for every other transect in order to make a
-    // lawnmower pattern
-    QList<QGeoCoordinate> transectVertices = transects[i];
-    if (reverseVertices) {
-      reverseVertices = false;
-      QList<QGeoCoordinate> reversedVertices;
-      for (int j = transectVertices.count() - 1; j >= 0; j--) {
-        reversedVertices.append(transectVertices[j]);
-      }
-      transectVertices = reversedVertices;
-    } else {
-      reverseVertices = true;
-    }
-    transects[i] = transectVertices;
-  }
-
-  // Convert to CoordInfo transects and append to _transects
-  for (const QList<QGeoCoordinate> &transect : transects) {
-    QGeoCoordinate coord;
-    QList<TransectStyleComplexItem::CoordInfo_t> coordInfoTransect;
-    TransectStyleComplexItem::CoordInfo_t coordInfo;
-
-    coordInfo = {transect[0], CoordTypeSurveyEntry};
-    coordInfoTransect.append(coordInfo);
-    coordInfo = {transect[1], CoordTypeSurveyExit};
-    coordInfoTransect.append(coordInfo);
-
-    // For hover and capture we need points for each camera location within the
-    // transect
-    if (triggerCamera() && hoverAndCaptureEnabled()) {
-      double transectLength = transect[0].distanceTo(transect[1]);
-      double transectAzimuth = transect[0].azimuthTo(transect[1]);
-      if (triggerDistance() < transectLength) {
-        int cInnerHoverPoints =
-            static_cast<int>(floor(transectLength / triggerDistance()));
-        qCDebug(SurveyComplexItemLog)
-            << "cInnerHoverPoints" << cInnerHoverPoints;
-        for (int i = 0; i < cInnerHoverPoints; i++) {
-          QGeoCoordinate hoverCoord = transect[0].atDistanceAndAzimuth(
-              triggerDistance() * (i + 1), transectAzimuth);
-          TransectStyleComplexItem::CoordInfo_t coordInfo = {
-              hoverCoord, CoordTypeInteriorHoverTrigger};
-          coordInfoTransect.insert(1 + i, coordInfo);
-        }
-      }
+    // Less than two transects intersected with the polygon:
+    //      Create a single transect which goes through the center of the polygon
+    //      Intersect it with the polygon
+    if (intersectLines.count() < 2) {
+        _surveyAreaPolygon.center();
+        QLineF firstLine = lineList.first();
+        QPointF lineCenter = firstLine.pointAt(0.5);
+        QPointF centerOffset = boundingCenter - lineCenter;
+        firstLine.translate(centerOffset);
+        lineList.clear();
+        lineList.append(firstLine);
+        intersectLines = lineList;
+        _intersectLinesWithPolygon(lineList, polygon, intersectLines);
     }
 
-    // Extend the transect ends for turnaround
-    if (_hasTurnaround()) {
-      QGeoCoordinate turnaroundCoord;
-      double turnAroundDistance = _turnAroundDistanceFact.rawValue().toDouble();
+    // Make sure all lines are going the same direction. Polygon intersection leads to lines which
+    // can be in varied directions depending on the order of the intesecting sides.
+    QList<QLineF> resultLines;
+    _adjustLineDirection(intersectLines, resultLines);
 
-      double azimuth = transect[0].azimuthTo(transect[1]);
-      turnaroundCoord =
-          transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
-      turnaroundCoord.setAltitude(qQNaN());
-      TransectStyleComplexItem::CoordInfo_t coordInfo = {turnaroundCoord,
-                                                         CoordTypeTurnaround};
-      coordInfoTransect.prepend(coordInfo);
+    // Convert from NED to Geo
+    QList<QList<QGeoCoordinate>> transects;
+    for (const QLineF& line : resultLines) {
+        QGeoCoordinate          coord;
+        QList<QGeoCoordinate>   transect;
 
-      azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
-      turnaroundCoord =
-          transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
-      turnaroundCoord.setAltitude(qQNaN());
-      coordInfo = {turnaroundCoord, CoordTypeTurnaround};
-      coordInfoTransect.append(coordInfo);
+        convertNedToGeo(line.p1().y(), line.p1().x(), 0, tangentOrigin, &coord);
+        transect.append(coord);
+        convertNedToGeo(line.p2().y(), line.p2().x(), 0, tangentOrigin, &coord);
+        transect.append(coord);
+
+        transects.append(transect);
     }
 
-    _transects.append(coordInfoTransect);
-  }
-}
+    _adjustTransectsToEntryPointLocation(transects);
 
-void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly) {
-  if (_ignoreRecalc) {
-    return;
-  }
-
-  // If the transects are getting rebuilt then any previously loaded mission
-  // items are now invalid
-  if (_loadedMissionItemsParent) {
-    _loadedMissionItems.clear();
-    _loadedMissionItemsParent->deleteLater();
-    _loadedMissionItemsParent = nullptr;
-  }
-
-  // First pass will clear old transect data, refly will append to existing data
-  if (!refly) {
-    _transects.clear();
-    _transectsPathHeightInfo.clear();
-  }
-
-  if (_surveyAreaPolygon.count() < 3) {
-    return;
-  }
-
-  // Convert polygon to NED
-
-  QList<QPointF> polygonPoints;
-  QGeoCoordinate tangentOrigin = _surveyAreaPolygon.pathModel()
-                                     .value<QGCQGeoCoordinate *>(0)
-                                     ->coordinate();
-  qCDebug(SurveyComplexItemLog)
-      << "_rebuildTransectsPhase1 Convert polygon to NED - "
-         "_surveyAreaPolygon.count():tangentOrigin"
-      << _surveyAreaPolygon.count() << tangentOrigin;
-  for (int i = 0; i < _surveyAreaPolygon.count(); i++) {
-    double y, x, down;
-    QGeoCoordinate vertex = _surveyAreaPolygon.pathModel()
-                                .value<QGCQGeoCoordinate *>(i)
-                                ->coordinate();
-    if (i == 0) {
-      // This avoids a nan calculation that comes out of convertGeoToNed
-      x = y = 0;
-    } else {
-      convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
-    }
-    polygonPoints += QPointF(x, y);
-    qCDebug(SurveyComplexItemLog)
-        << "_rebuildTransectsPhase1 vertex:x:y" << vertex
-        << polygonPoints.last().x() << polygonPoints.last().y();
-  }
-
-  // convert into QPolygonF
-  QPolygonF polygon;
-  for (int i = 0; i < polygonPoints.count(); i++) {
-    qCDebug(SurveyComplexItemLog) << "Vertex" << polygonPoints[i];
-    polygon << polygonPoints[i];
-  }
-
-  // Create list of separate polygons
-  QList<QPolygonF> polygons{};
-  _PolygonDecomposeConvex(polygon, polygons);
-
-  // iterate over polygons
-  for (auto p = polygons.begin(); p != polygons.end(); ++p) {
-    QPointF *vMatch = nullptr;
-    // find matching vertex in previous polygon
-    if (p != polygons.begin()) {
-      auto pLast = p - 1;
-      for (auto &i : *p) {
-        for (auto &j : *pLast) {
-          if (i == j) {
-            vMatch = &i;
-            break;
-          }
-          if (vMatch)
-            break;
+    if (refly) {
+        _optimizeTransectsForShortestDistance(_transects.last().last().coord, transects);
+    }
+
+    if (_flyAlternateTransectsFact.rawValue().toBool()) {
+        QList<QList<QGeoCoordinate>> alternatingTransects;
+        for (int i=0; i<transects.count(); i++) {
+            if (!(i & 1)) {
+                alternatingTransects.append(transects[i]);
+            }
+        }
+        for (int i=transects.count()-1; i>0; i--) {
+            if (i & 1) {
+                alternatingTransects.append(transects[i]);
+            }
+        }
+        transects = alternatingTransects;
+    }
+
+    // Adjust to lawnmower pattern
+    bool reverseVertices = false;
+    for (int i=0; i<transects.count(); i++) {
+        // We must reverse the vertices for every other transect in order to make a lawnmower pattern
+        QList<QGeoCoordinate> transectVertices = transects[i];
+        if (reverseVertices) {
+            reverseVertices = false;
+            QList<QGeoCoordinate> reversedVertices;
+            for (int j=transectVertices.count()-1; j>=0; j--) {
+                reversedVertices.append(transectVertices[j]);
+            }
+            transectVertices = reversedVertices;
+        } else {
+            reverseVertices = true;
         }
-      }
+        transects[i] = transectVertices;
     }
 
-    // close polygon
-    *p << p->front();
-    // build transects for this polygon
-    // TODO figure out tangent origin
-    // TODO improve selection of entry points
-    //        qCDebug(SurveyComplexItemLog) << "Transects from polynom p " << p;
-    _rebuildTransectsFromPolygon(refly, *p, tangentOrigin, vMatch);
-  }
+    // Convert to CoordInfo transects and append to _transects
+    for (const QList<QGeoCoordinate>& transect : transects) {
+        QGeoCoordinate                                  coord;
+        QList<TransectStyleComplexItem::CoordInfo_t>    coordInfoTransect;
+        TransectStyleComplexItem::CoordInfo_t           coordInfo;
+
+        coordInfo = { transect[0], CoordTypeSurveyEntry };
+        coordInfoTransect.append(coordInfo);
+        coordInfo = { transect[1], CoordTypeSurveyExit };
+        coordInfoTransect.append(coordInfo);
+
+        // For hover and capture we need points for each camera location within the transect
+        if (triggerCamera() && hoverAndCaptureEnabled()) {
+            double transectLength = transect[0].distanceTo(transect[1]);
+            double transectAzimuth = transect[0].azimuthTo(transect[1]);
+            if (triggerDistance() < transectLength) {
+                int cInnerHoverPoints = static_cast<int>(floor(transectLength / triggerDistance()));
+                qCDebug(SurveyComplexItemLog) << "cInnerHoverPoints" << cInnerHoverPoints;
+                for (int i=0; i<cInnerHoverPoints; i++) {
+                    QGeoCoordinate hoverCoord = transect[0].atDistanceAndAzimuth(triggerDistance() * (i + 1), transectAzimuth);
+                    TransectStyleComplexItem::CoordInfo_t coordInfo = { hoverCoord, CoordTypeInteriorHoverTrigger };
+                    coordInfoTransect.insert(1 + i, coordInfo);
+                }
+            }
+        }
+
+        // Extend the transect ends for turnaround
+        if (_hasTurnaround()) {
+            QGeoCoordinate turnaroundCoord;
+            double turnAroundDistance = _turnAroundDistanceFact.rawValue().toDouble();
+
+            double azimuth = transect[0].azimuthTo(transect[1]);
+            turnaroundCoord = transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
+            turnaroundCoord.setAltitude(qQNaN());
+            TransectStyleComplexItem::CoordInfo_t coordInfo = { turnaroundCoord, CoordTypeTurnaround };
+            coordInfoTransect.prepend(coordInfo);
+
+            azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
+            turnaroundCoord = transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
+            turnaroundCoord.setAltitude(qQNaN());
+            coordInfo = { turnaroundCoord, CoordTypeTurnaround };
+            coordInfoTransect.append(coordInfo);
+        }
+
+        _transects.append(coordInfoTransect);
+    }
 }
 
-void SurveyComplexItem::_PolygonDecomposeConvex(
-    const QPolygonF &polygon, QList<QPolygonF> &decomposedPolygons) {
-  // this follows "Mark Keil's Algorithm" https://mpen.ca/406/keil
-  int decompSize = std::numeric_limits<int>::max();
-  if (polygon.size() < 3)
-    return;
-  if (polygon.size() == 3) {
-    decomposedPolygons << polygon;
-    return;
-  }
-
-  QList<QPolygonF> decomposedPolygonsMin{};
-
-  for (auto vertex = polygon.begin(); vertex != polygon.end(); ++vertex) {
-    // is vertex reflex?
-    bool vertexIsReflex = _VertexIsReflex(polygon, vertex);
-
-    if (!vertexIsReflex)
-      continue;
-
-    for (auto vertexOther = polygon.begin(); vertexOther != polygon.end();
-         ++vertexOther) {
-      auto vertexBefore =
-          vertex == polygon.begin() ? polygon.end() - 1 : vertex - 1;
-      auto vertexAfter =
-          vertex == polygon.end() - 1 ? polygon.begin() : vertex + 1;
-      if (vertexOther == vertex)
-        continue;
-      if (vertexAfter == vertexOther)
-        continue;
-      if (vertexBefore == vertexOther)
-        continue;
-      bool canSee = _VertexCanSeeOther(polygon, vertex, vertexOther);
-      if (!canSee)
-        continue;
-
-      QPolygonF polyLeft;
-      auto v = vertex;
-      auto polyLeftContainsReflex = false;
-      while (v != vertexOther) {
-        if (v != vertex && _VertexIsReflex(polygon, v)) {
-          polyLeftContainsReflex = true;
+
+void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly)
+{
+    if (_ignoreRecalc) {
+        return;
+    }
+
+    // If the transects are getting rebuilt then any previously loaded mission items are now invalid
+    if (_loadedMissionItemsParent) {
+        _loadedMissionItems.clear();
+        _loadedMissionItemsParent->deleteLater();
+        _loadedMissionItemsParent = nullptr;
+    }
+
+    // First pass will clear old transect data, refly will append to existing data
+    if (!refly) {
+        _transects.clear();
+        _transectsPathHeightInfo.clear();
+    }
+
+    if (_surveyAreaPolygon.count() < 3) {
+        return;
+    }
+
+    // Convert polygon to NED
+
+    QList<QPointF> polygonPoints;
+    QGeoCoordinate tangentOrigin = _surveyAreaPolygon.pathModel().value<QGCQGeoCoordinate*>(0)->coordinate();
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Convert polygon to NED - _surveyAreaPolygon.count():tangentOrigin" << _surveyAreaPolygon.count() << tangentOrigin;
+    for (int i=0; i<_surveyAreaPolygon.count(); i++) {
+        double y, x, down;
+        QGeoCoordinate vertex = _surveyAreaPolygon.pathModel().value<QGCQGeoCoordinate*>(i)->coordinate();
+        if (i == 0) {
+            // This avoids a nan calculation that comes out of convertGeoToNed
+            x = y = 0;
+        } else {
+            convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
         }
-        polyLeft << *v;
-        ++v;
-        if (v == polygon.end())
-          v = polygon.begin();
-      }
-      polyLeft << *vertexOther;
-      auto polyLeftValid = !(polyLeftContainsReflex && polyLeft.size() == 3);
-
-      QPolygonF polyRight;
-      v = vertexOther;
-      auto polyRightContainsReflex = false;
-      while (v != vertex) {
-        if (v != vertex && _VertexIsReflex(polygon, v)) {
-          polyRightContainsReflex = true;
+        polygonPoints += QPointF(x, y);
+        qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 vertex:x:y" << vertex << polygonPoints.last().x() << polygonPoints.last().y();
+    }
+
+    // convert into QPolygonF
+    QPolygonF polygon;
+    for (int i=0; i<polygonPoints.count(); i++) {
+        qCDebug(SurveyComplexItemLog) << "Vertex" << polygonPoints[i];
+        polygon << polygonPoints[i];
+    }
+
+    // Create list of separate polygons
+    QList<QPolygonF> polygons{};
+    _PolygonDecomposeConvex(polygon, polygons);
+
+    // iterate over polygons
+    for (auto p = polygons.begin(); p != polygons.end(); ++p) {
+        QPointF* vMatch = nullptr;
+        // find matching vertex in previous polygon
+        if (p != polygons.begin()) {
+            auto pLast = p - 1;
+            for (auto& i : *p) {
+                for (auto& j : *pLast) {
+                   if (i == j) {
+                       vMatch = &i;
+                       break;
+                   }
+                   if (vMatch) break;
+                }
+            }
+
         }
-        polyRight << *v;
-        ++v;
-        if (v == polygon.end())
-          v = polygon.begin();
-      }
-      polyRight << *vertex;
-      auto polyRightValid = !(polyRightContainsReflex && polyRight.size() == 3);
-
-      if (!polyLeftValid || !polyRightValid) {
-        //                decompSize = std::numeric_limits<int>::max();
-        continue;
-      }
-
-      // recursion
-      QList<QPolygonF> polyLeftDecomposed{};
-      _PolygonDecomposeConvex(polyLeft, polyLeftDecomposed);
-
-      QList<QPolygonF> polyRightDecomposed{};
-      _PolygonDecomposeConvex(polyRight, polyRightDecomposed);
-
-      // compositon
-      auto subSize = polyLeftDecomposed.size() + polyRightDecomposed.size();
-      if ((polyLeftContainsReflex && polyLeftDecomposed.size() == 1) ||
-          (polyRightContainsReflex && polyRightDecomposed.size() == 1)) {
-        // don't accept polygons that contian reflex vertices and were not split
-        subSize = std::numeric_limits<int>::max();
-      }
-      if (subSize < decompSize) {
-        decompSize = subSize;
-        decomposedPolygonsMin = polyLeftDecomposed + polyRightDecomposed;
-      }
-    }
-  }
-
-  // assemble output
-  if (decomposedPolygonsMin.size() > 0) {
-    decomposedPolygons << decomposedPolygonsMin;
-  } else {
-    decomposedPolygons << polygon;
-  }
-
-  return;
+
+
+        // close polygon
+        *p << p->front();
+        // build transects for this polygon
+        // TODO figure out tangent origin
+        // TODO improve selection of entry points
+//        qCDebug(SurveyComplexItemLog) << "Transects from polynom p " << p;
+        _rebuildTransectsFromPolygon(refly, *p, tangentOrigin, vMatch);
+    }
 }
 
-bool SurveyComplexItem::_VertexCanSeeOther(const QPolygonF &polygon,
-                                           const QPointF *vertexA,
-                                           const QPointF *vertexB) {
-  if (vertexA == vertexB)
-    return false;
-  auto vertexAAfter =
-      vertexA + 1 == polygon.end() ? polygon.begin() : vertexA + 1;
-  auto vertexABefore =
-      vertexA == polygon.begin() ? polygon.end() - 1 : vertexA - 1;
-  if (vertexAAfter == vertexB)
-    return false;
-  if (vertexABefore == vertexB)
-    return false;
-  //    qCDebug(SurveyComplexItemLog) << "_VertexCanSeeOther false after first
-  //    checks ";
-
-  bool visible = true;
-  //    auto diff = *vertexA - *vertexB;
-  QLineF lineAB{*vertexA, *vertexB};
-  auto distanceAB =
-      lineAB.length(); // sqrtf(diff.x() * diff.x() + diff.y()*diff.y());
-
-  //    qCDebug(SurveyComplexItemLog) << "_VertexCanSeeOther distanceAB " <<
-  //    distanceAB;
-  for (auto vertexC = polygon.begin(); vertexC != polygon.end(); ++vertexC) {
-    if (vertexC == vertexA)
-      continue;
-    if (vertexC == vertexB)
-      continue;
-    auto vertexD = vertexC + 1 == polygon.end() ? polygon.begin() : vertexC + 1;
-    if (vertexD == vertexA)
-      continue;
-    if (vertexD == vertexB)
-      continue;
-    QLineF lineCD(*vertexC, *vertexD);
-    QPointF intersection{};
+void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<QPolygonF>& decomposedPolygons)
+{
+	// this follows "Mark Keil's Algorithm" https://mpen.ca/406/keil
+    int decompSize = std::numeric_limits<int>::max();
+    if (polygon.size() < 3) return;
+    if (polygon.size() == 3) {
+        decomposedPolygons << polygon;
+        return;
+    }
+
+    QList<QPolygonF> decomposedPolygonsMin{};
+
+    for (auto vertex = polygon.begin(); vertex != polygon.end(); ++vertex)
+    {
+        // is vertex reflex?
+        bool vertexIsReflex = _VertexIsReflex(polygon, vertex);
+
+        if (!vertexIsReflex) continue;
+
+        for (auto vertexOther = polygon.begin(); vertexOther != polygon.end(); ++vertexOther)
+        {
+            auto vertexBefore = vertex == polygon.begin() ? polygon.end() - 1 : vertex - 1;
+            auto vertexAfter = vertex == polygon.end() - 1 ? polygon.begin() : vertex + 1;
+            if (vertexOther == vertex) continue;
+            if (vertexAfter == vertexOther) continue;
+            if (vertexBefore == vertexOther) continue;
+            bool canSee = _VertexCanSeeOther(polygon, vertex, vertexOther);
+            if (!canSee) continue;
+
+            QPolygonF polyLeft;
+            auto v = vertex;
+            auto polyLeftContainsReflex = false;
+            while ( v != vertexOther) {
+                if (v != vertex && _VertexIsReflex(polygon, v)) {
+                    polyLeftContainsReflex = true;
+                }
+                polyLeft << *v;
+                ++v;
+                if (v == polygon.end()) v = polygon.begin();
+            }
+            polyLeft << *vertexOther;
+            auto polyLeftValid = !(polyLeftContainsReflex && polyLeft.size() == 3);
+
+            QPolygonF polyRight;
+            v = vertexOther;
+            auto polyRightContainsReflex = false;
+            while ( v != vertex) {
+                if (v != vertex && _VertexIsReflex(polygon, v)) {
+                    polyRightContainsReflex = true;
+                }
+                polyRight << *v;
+                ++v;
+                if (v == polygon.end()) v = polygon.begin();
+            }
+            polyRight << *vertex;
+            auto polyRightValid = !(polyRightContainsReflex && polyRight.size() == 3);
+
+            if (!polyLeftValid || ! polyRightValid) {
+//                decompSize = std::numeric_limits<int>::max();
+                continue;
+            }
+
+            // recursion
+            QList<QPolygonF> polyLeftDecomposed{};
+            _PolygonDecomposeConvex(polyLeft, polyLeftDecomposed);
+
+            QList<QPolygonF> polyRightDecomposed{};
+            _PolygonDecomposeConvex(polyRight, polyRightDecomposed);
+
+            // compositon
+            auto subSize = polyLeftDecomposed.size() + polyRightDecomposed.size();
+            if ((polyLeftContainsReflex && polyLeftDecomposed.size() == 1)
+                    || (polyRightContainsReflex && polyRightDecomposed.size() == 1))
+            {
+                // don't accept polygons that contian reflex vertices and were not split
+                subSize = std::numeric_limits<int>::max();
+            }
+            if (subSize < decompSize) {
+                decompSize = subSize;
+                decomposedPolygonsMin = polyLeftDecomposed + polyRightDecomposed;
+            }
+        }
+
+    }
+
+    // assemble output
+    if (decomposedPolygonsMin.size() > 0) {
+        decomposedPolygons << decomposedPolygonsMin;
+    } else {
+        decomposedPolygons << polygon;
+    }
+
+    return;
+}
+
+bool SurveyComplexItem::_VertexCanSeeOther(const QPolygonF& polygon, const QPointF* vertexA, const QPointF* vertexB) {
+    if (vertexA == vertexB) return false;
+    auto vertexAAfter = vertexA + 1 == polygon.end() ? polygon.begin() : vertexA + 1;
+    auto vertexABefore = vertexA == polygon.begin() ? polygon.end() - 1 : vertexA - 1;
+    if (vertexAAfter == vertexB) return false;
+    if (vertexABefore == vertexB) return false;
+//    qCDebug(SurveyComplexItemLog) << "_VertexCanSeeOther false after first checks ";
+
+    bool visible = true;
+//    auto diff = *vertexA - *vertexB;
+    QLineF lineAB{*vertexA, *vertexB};
+    auto distanceAB = lineAB.length();//sqrtf(diff.x() * diff.x() + diff.y()*diff.y());
+
+//    qCDebug(SurveyComplexItemLog) << "_VertexCanSeeOther distanceAB " << distanceAB;
+    for (auto vertexC = polygon.begin(); vertexC != polygon.end(); ++vertexC)
+    {
+        if (vertexC == vertexA) continue;
+        if (vertexC == vertexB) continue;
+        auto vertexD = vertexC + 1 == polygon.end() ? polygon.begin() : vertexC + 1;
+        if (vertexD == vertexA) continue;
+        if (vertexD == vertexB) continue;
+        QLineF lineCD(*vertexC, *vertexD);
+        QPointF intersection{};
 
 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
-    auto intersects = lineAB.intersect(lineCD, &intersection);
+        auto intersects = lineAB.intersect(lineCD, &intersection);
 #else
-    auto intersects = lineAB.intersects(lineCD, &intersection);
+        auto intersects = lineAB.intersects(lineCD, &intersection);
 #endif
-    if (intersects == QLineF::IntersectType::BoundedIntersection) {
-      //            auto diffIntersection = *vertexA - intersection;
-      //            auto distanceIntersection = sqrtf(diffIntersection.x() *
-      //            diffIntersection.x() +
-      //            diffIntersection.y()*diffIntersection.y());
-      //            qCDebug(SurveyComplexItemLog) << "*vertexA " << *vertexA <<
-      //            "*vertexB " << *vertexB  << " intersection " <<
-      //            intersection;
-
-      QLineF lineIntersection{*vertexA, intersection};
-      auto distanceIntersection =
-          lineIntersection
-              .length(); // sqrtf(diff.x() * diff.x() + diff.y()*diff.y());
-      qCDebug(SurveyComplexItemLog)
-          << "_VertexCanSeeOther distanceIntersection " << distanceIntersection;
-      if (distanceIntersection < distanceAB) {
-        visible = false;
-        break;
-      }
-    }
-  }
-
-  return visible;
+        if (intersects == QLineF::IntersectType::BoundedIntersection) {
+//            auto diffIntersection = *vertexA - intersection;
+//            auto distanceIntersection = sqrtf(diffIntersection.x() * diffIntersection.x() + diffIntersection.y()*diffIntersection.y());
+//            qCDebug(SurveyComplexItemLog) << "*vertexA " << *vertexA << "*vertexB " << *vertexB  << " intersection " << intersection;
+
+            QLineF lineIntersection{*vertexA, intersection};
+            auto distanceIntersection = lineIntersection.length();//sqrtf(diff.x() * diff.x() + diff.y()*diff.y());
+            qCDebug(SurveyComplexItemLog) << "_VertexCanSeeOther distanceIntersection " << distanceIntersection;
+            if (distanceIntersection < distanceAB) {
+                visible = false;
+                break;
+            }
+        }
+
+    }
+
+    return visible;
 }
 
-bool SurveyComplexItem::_VertexIsReflex(const QPolygonF &polygon,
-                                        const QPointF *vertex) {
-  auto vertexBefore =
-      vertex == polygon.begin() ? polygon.end() - 1 : vertex - 1;
-  auto vertexAfter = vertex == polygon.end() - 1 ? polygon.begin() : vertex + 1;
-  auto area = (((vertex->x() - vertexBefore->x()) *
-                (vertexAfter->y() - vertexBefore->y())) -
-               ((vertexAfter->x() - vertexBefore->x()) *
-                (vertex->y() - vertexBefore->y())));
-  return area > 0;
+bool SurveyComplexItem::_VertexIsReflex(const QPolygonF& polygon, const QPointF* vertex) {
+    auto vertexBefore = vertex == polygon.begin() ? polygon.end() - 1 : vertex - 1;
+    auto vertexAfter = vertex == polygon.end() - 1 ? polygon.begin() : vertex + 1;
+    auto area = (((vertex->x() - vertexBefore->x())*(vertexAfter->y() - vertexBefore->y()))-((vertexAfter->x() - vertexBefore->x())*(vertex->y() - vertexBefore->y())));
+    return area > 0;
+
 }
 
-void SurveyComplexItem::_rebuildTransectsFromPolygon(
-    bool refly, const QPolygonF &polygon, const QGeoCoordinate &tangentOrigin,
-    const QPointF *const transitionPoint) {
-  // Generate transects
-
-  double gridAngle = _gridAngleFact.rawValue().toDouble();
-  double gridSpacing =
-      _cameraCalc.adjustedFootprintSide()->rawValue().toDouble();
-
-  gridAngle = _clampGridAngle90(gridAngle);
-  gridAngle += refly ? 90 : 0;
-  qCDebug(SurveyComplexItemLog)
-      << "_rebuildTransectsPhase1 Clamped grid angle" << gridAngle;
-
-  qCDebug(SurveyComplexItemLog)
-      << "_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing
-      << gridAngle << refly;
-
-  // Convert polygon to bounding rect
-
-  qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Polygon";
-  QRectF boundingRect = polygon.boundingRect();
-  QPointF boundingCenter = boundingRect.center();
-  qCDebug(SurveyComplexItemLog)
-      << "Bounding rect" << boundingRect.topLeft().x()
-      << boundingRect.topLeft().y() << boundingRect.bottomRight().x()
-      << boundingRect.bottomRight().y();
-
-  // Create set of rotated parallel lines within the expanded bounding rect.
-  // Make the lines larger than the bounding box to guarantee intersection.
-
-  QList<QLineF> lineList;
-
-  // Transects are generated to be as long as the largest width/height of the
-  // bounding rect plus some fudge factor. This way they will always be
-  // guaranteed to intersect with a polygon edge no matter what angle they are
-  // rotated to. They are initially generated with the transects flowing from
-  // west to east and then points within the transect north to south.
-  double maxWidth = qMax(boundingRect.width(), boundingRect.height()) + 2000.0;
-  double halfWidth = maxWidth / 2.0;
-  double transectX = boundingCenter.x() - halfWidth;
-  double transectXMax = transectX + maxWidth;
-  while (transectX < transectXMax) {
-    double transectYTop = boundingCenter.y() - halfWidth;
-    double transectYBottom = boundingCenter.y() + halfWidth;
-
-    lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop),
-                                    boundingCenter, gridAngle),
-                       _rotatePoint(QPointF(transectX, transectYBottom),
-                                    boundingCenter, gridAngle));
-    transectX += gridSpacing;
-  }
-
-  // Now intersect the lines with the polygon
-  QList<QLineF> intersectLines;
+
+void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF& polygon, const QGeoCoordinate& tangentOrigin, const QPointF* const transitionPoint)
+{
+    // Generate transects
+
+    double gridAngle = _gridAngleFact.rawValue().toDouble();
+    double gridSpacing = _cameraCalc.adjustedFootprintSide()->rawValue().toDouble();
+
+    gridAngle = _clampGridAngle90(gridAngle);
+    gridAngle += refly ? 90 : 0;
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Clamped grid angle" << gridAngle;
+
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing << gridAngle << refly;
+
+    // Convert polygon to bounding rect
+
+    qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Polygon";
+    QRectF boundingRect = polygon.boundingRect();
+    QPointF boundingCenter = boundingRect.center();
+    qCDebug(SurveyComplexItemLog) << "Bounding rect" << boundingRect.topLeft().x() << boundingRect.topLeft().y() << boundingRect.bottomRight().x() << boundingRect.bottomRight().y();
+
+    // Create set of rotated parallel lines within the expanded bounding rect. Make the lines larger than the
+    // bounding box to guarantee intersection.
+
+    QList<QLineF> lineList;
+
+    // Transects are generated to be as long as the largest width/height of the bounding rect plus some fudge factor.
+    // This way they will always be guaranteed to intersect with a polygon edge no matter what angle they are rotated to.
+    // They are initially generated with the transects flowing from west to east and then points within the transect north to south.
+    double maxWidth = qMax(boundingRect.width(), boundingRect.height()) + 2000.0;
+    double halfWidth = maxWidth / 2.0;
+    double transectX = boundingCenter.x() - halfWidth;
+    double transectXMax = transectX + maxWidth;
+    while (transectX < transectXMax) {
+        double transectYTop = boundingCenter.y() - halfWidth;
+        double transectYBottom = boundingCenter.y() + halfWidth;
+
+        lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop), boundingCenter, gridAngle), _rotatePoint(QPointF(transectX, transectYBottom), boundingCenter, gridAngle));
+        transectX += gridSpacing;
+    }
+
+    // Now intersect the lines with the polygon
+    QList<QLineF> intersectLines;
 #if 1
-  _intersectLinesWithPolygon(lineList, polygon, intersectLines);
+    _intersectLinesWithPolygon(lineList, polygon, intersectLines);
 #else
-  // This is handy for debugging grid problems, not for release
-  intersectLines = lineList;
+    // This is handy for debugging grid problems, not for release
+    intersectLines = lineList;
 #endif
 
-  // Less than two transects intersected with the polygon:
-  //      Create a single transect which goes through the center of the polygon
-  //      Intersect it with the polygon
-  if (intersectLines.count() < 2) {
-    _surveyAreaPolygon.center();
-    QLineF firstLine = lineList.first();
-    QPointF lineCenter = firstLine.pointAt(0.5);
-    QPointF centerOffset = boundingCenter - lineCenter;
-    firstLine.translate(centerOffset);
-    lineList.clear();
-    lineList.append(firstLine);
-    intersectLines = lineList;
-    _intersectLinesWithPolygon(lineList, polygon, intersectLines);
-  }
-
-  // Make sure all lines are going the same direction. Polygon intersection
-  // leads to lines which can be in varied directions depending on the order of
-  // the intesecting sides.
-  QList<QLineF> resultLines;
-  _adjustLineDirection(intersectLines, resultLines);
-
-  // Convert from NED to Geo
-  QList<QList<QGeoCoordinate>> transects;
-
-  if (transitionPoint != nullptr) {
-    QList<QGeoCoordinate> transect;
-    QGeoCoordinate coord;
-    convertNedToGeo(transitionPoint->y(), transitionPoint->x(), 0,
-                    tangentOrigin, &coord);
-    transect.append(coord);
-    transect.append(coord); // TODO
-    transects.append(transect);
-  }
-
-  for (const QLineF &line : resultLines) {
-    QList<QGeoCoordinate> transect;
-    QGeoCoordinate coord;
-
-    convertNedToGeo(line.p1().y(), line.p1().x(), 0, tangentOrigin, &coord);
-    transect.append(coord);
-    convertNedToGeo(line.p2().y(), line.p2().x(), 0, tangentOrigin, &coord);
-    transect.append(coord);
-
-    transects.append(transect);
-  }
-
-  _adjustTransectsToEntryPointLocation(transects);
-
-  if (refly) {
-    _optimizeTransectsForShortestDistance(_transects.last().last().coord,
-                                          transects);
-  }
-
-  if (_flyAlternateTransectsFact.rawValue().toBool()) {
-    QList<QList<QGeoCoordinate>> alternatingTransects;
-    for (int i = 0; i < transects.count(); i++) {
-      if (!(i & 1)) {
-        alternatingTransects.append(transects[i]);
-      }
-    }
-    for (int i = transects.count() - 1; i > 0; i--) {
-      if (i & 1) {
-        alternatingTransects.append(transects[i]);
-      }
-    }
-    transects = alternatingTransects;
-  }
-
-  // Adjust to lawnmower pattern
-  bool reverseVertices = false;
-  for (int i = 0; i < transects.count(); i++) {
-    // We must reverse the vertices for every other transect in order to make a
-    // lawnmower pattern
-    QList<QGeoCoordinate> transectVertices = transects[i];
-    if (reverseVertices) {
-      reverseVertices = false;
-      QList<QGeoCoordinate> reversedVertices;
-      for (int j = transectVertices.count() - 1; j >= 0; j--) {
-        reversedVertices.append(transectVertices[j]);
-      }
-      transectVertices = reversedVertices;
-    } else {
-      reverseVertices = true;
-    }
-    transects[i] = transectVertices;
-  }
-
-  // Convert to CoordInfo transects and append to _transects
-  for (const QList<QGeoCoordinate> &transect : transects) {
-    QGeoCoordinate coord;
-    QList<TransectStyleComplexItem::CoordInfo_t> coordInfoTransect;
-    TransectStyleComplexItem::CoordInfo_t coordInfo;
-
-    coordInfo = {transect[0], CoordTypeSurveyEntry};
-    coordInfoTransect.append(coordInfo);
-    coordInfo = {transect[1], CoordTypeSurveyExit};
-    coordInfoTransect.append(coordInfo);
-
-    // For hover and capture we need points for each camera location within the
-    // transect
-    if (triggerCamera() && hoverAndCaptureEnabled()) {
-      double transectLength = transect[0].distanceTo(transect[1]);
-      double transectAzimuth = transect[0].azimuthTo(transect[1]);
-      if (triggerDistance() < transectLength) {
-        int cInnerHoverPoints =
-            static_cast<int>(floor(transectLength / triggerDistance()));
-        qCDebug(SurveyComplexItemLog)
-            << "cInnerHoverPoints" << cInnerHoverPoints;
-        for (int i = 0; i < cInnerHoverPoints; i++) {
-          QGeoCoordinate hoverCoord = transect[0].atDistanceAndAzimuth(
-              triggerDistance() * (i + 1), transectAzimuth);
-          TransectStyleComplexItem::CoordInfo_t coordInfo = {
-              hoverCoord, CoordTypeInteriorHoverTrigger};
-          coordInfoTransect.insert(1 + i, coordInfo);
-        }
-      }
+    // Less than two transects intersected with the polygon:
+    //      Create a single transect which goes through the center of the polygon
+    //      Intersect it with the polygon
+    if (intersectLines.count() < 2) {
+        _surveyAreaPolygon.center();
+        QLineF firstLine = lineList.first();
+        QPointF lineCenter = firstLine.pointAt(0.5);
+        QPointF centerOffset = boundingCenter - lineCenter;
+        firstLine.translate(centerOffset);
+        lineList.clear();
+        lineList.append(firstLine);
+        intersectLines = lineList;
+        _intersectLinesWithPolygon(lineList, polygon, intersectLines);
     }
 
-    // Extend the transect ends for turnaround
-    if (_hasTurnaround()) {
-      QGeoCoordinate turnaroundCoord;
-      double turnAroundDistance = _turnAroundDistanceFact.rawValue().toDouble();
+    // Make sure all lines are going the same direction. Polygon intersection leads to lines which
+    // can be in varied directions depending on the order of the intesecting sides.
+    QList<QLineF> resultLines;
+    _adjustLineDirection(intersectLines, resultLines);
+
+    // Convert from NED to Geo
+    QList<QList<QGeoCoordinate>> transects;
+
+    if (transitionPoint != nullptr) {
+        QList<QGeoCoordinate>   transect;
+        QGeoCoordinate          coord;
+        convertNedToGeo(transitionPoint->y(), transitionPoint->x(), 0, tangentOrigin, &coord);
+        transect.append(coord);
+        transect.append(coord); //TODO
+        transects.append(transect);
+    }
+
+    for (const QLineF& line: resultLines) {
+        QList<QGeoCoordinate>   transect;
+        QGeoCoordinate          coord;
 
-      double azimuth = transect[0].azimuthTo(transect[1]);
-      turnaroundCoord =
-          transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
-      turnaroundCoord.setAltitude(qQNaN());
-      TransectStyleComplexItem::CoordInfo_t coordInfo = {turnaroundCoord,
-                                                         CoordTypeTurnaround};
-      coordInfoTransect.prepend(coordInfo);
+        convertNedToGeo(line.p1().y(), line.p1().x(), 0, tangentOrigin, &coord);
+        transect.append(coord);
+        convertNedToGeo(line.p2().y(), line.p2().x(), 0, tangentOrigin, &coord);
+        transect.append(coord);
 
-      azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
-      turnaroundCoord =
-          transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
-      turnaroundCoord.setAltitude(qQNaN());
-      coordInfo = {turnaroundCoord, CoordTypeTurnaround};
-      coordInfoTransect.append(coordInfo);
+        transects.append(transect);
     }
 
-    _transects.append(coordInfoTransect);
-  }
-  qCDebug(SurveyComplexItemLog) << "_transects.size() " << _transects.size();
+    _adjustTransectsToEntryPointLocation(transects);
+
+    if (refly) {
+        _optimizeTransectsForShortestDistance(_transects.last().last().coord, transects);
+    }
+
+    if (_flyAlternateTransectsFact.rawValue().toBool()) {
+        QList<QList<QGeoCoordinate>> alternatingTransects;
+        for (int i=0; i<transects.count(); i++) {
+            if (!(i & 1)) {
+                alternatingTransects.append(transects[i]);
+            }
+        }
+        for (int i=transects.count()-1; i>0; i--) {
+            if (i & 1) {
+                alternatingTransects.append(transects[i]);
+            }
+        }
+        transects = alternatingTransects;
+    }
+
+    // Adjust to lawnmower pattern
+    bool reverseVertices = false;
+    for (int i=0; i<transects.count(); i++) {
+        // We must reverse the vertices for every other transect in order to make a lawnmower pattern
+        QList<QGeoCoordinate> transectVertices = transects[i];
+        if (reverseVertices) {
+            reverseVertices = false;
+            QList<QGeoCoordinate> reversedVertices;
+            for (int j=transectVertices.count()-1; j>=0; j--) {
+                reversedVertices.append(transectVertices[j]);
+            }
+            transectVertices = reversedVertices;
+        } else {
+            reverseVertices = true;
+        }
+        transects[i] = transectVertices;
+    }
+
+    // Convert to CoordInfo transects and append to _transects
+    for (const QList<QGeoCoordinate>& transect: transects) {
+        QGeoCoordinate                                  coord;
+        QList<TransectStyleComplexItem::CoordInfo_t>    coordInfoTransect;
+        TransectStyleComplexItem::CoordInfo_t           coordInfo;
+
+        coordInfo = { transect[0], CoordTypeSurveyEntry };
+        coordInfoTransect.append(coordInfo);
+        coordInfo = { transect[1], CoordTypeSurveyExit };
+        coordInfoTransect.append(coordInfo);
+
+        // For hover and capture we need points for each camera location within the transect
+        if (triggerCamera() && hoverAndCaptureEnabled()) {
+            double transectLength = transect[0].distanceTo(transect[1]);
+            double transectAzimuth = transect[0].azimuthTo(transect[1]);
+            if (triggerDistance() < transectLength) {
+                int cInnerHoverPoints = static_cast<int>(floor(transectLength / triggerDistance()));
+                qCDebug(SurveyComplexItemLog) << "cInnerHoverPoints" << cInnerHoverPoints;
+                for (int i=0; i<cInnerHoverPoints; i++) {
+                    QGeoCoordinate hoverCoord = transect[0].atDistanceAndAzimuth(triggerDistance() * (i + 1), transectAzimuth);
+                    TransectStyleComplexItem::CoordInfo_t coordInfo = { hoverCoord, CoordTypeInteriorHoverTrigger };
+                    coordInfoTransect.insert(1 + i, coordInfo);
+                }
+            }
+        }
+
+        // Extend the transect ends for turnaround
+        if (_hasTurnaround()) {
+            QGeoCoordinate turnaroundCoord;
+            double turnAroundDistance = _turnAroundDistanceFact.rawValue().toDouble();
+
+            double azimuth = transect[0].azimuthTo(transect[1]);
+            turnaroundCoord = transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
+            turnaroundCoord.setAltitude(qQNaN());
+            TransectStyleComplexItem::CoordInfo_t coordInfo = { turnaroundCoord, CoordTypeTurnaround };
+            coordInfoTransect.prepend(coordInfo);
+
+            azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
+            turnaroundCoord = transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
+            turnaroundCoord.setAltitude(qQNaN());
+            coordInfo = { turnaroundCoord, CoordTypeTurnaround };
+            coordInfoTransect.append(coordInfo);
+        }
+
+        _transects.append(coordInfoTransect);
+    }
+    qCDebug(SurveyComplexItemLog) << "_transects.size() " << _transects.size();
 }
 
-void SurveyComplexItem::_recalcCameraShots(void) {
-  double triggerDistance = this->triggerDistance();
+void SurveyComplexItem::_recalcCameraShots(void)
+{
+    double triggerDistance = this->triggerDistance();
 
-  if (triggerDistance == 0) {
-    _cameraShots = 0;
-  } else {
-    if (_cameraTriggerInTurnAroundFact.rawValue().toBool()) {
-      _cameraShots = qCeil(_complexDistance / triggerDistance);
+    if (triggerDistance == 0) {
+        _cameraShots = 0;
     } else {
-      _cameraShots = 0;
-
-      if (_loadedMissionItemsParent) {
-        // We have to do it the hard way based on the mission items themselves
-        if (hoverAndCaptureEnabled()) {
-          // Count the number of camera triggers in the mission items
-          for (const MissionItem *missionItem : _loadedMissionItems) {
-            _cameraShots +=
-                missionItem->command() == MAV_CMD_IMAGE_START_CAPTURE ? 1 : 0;
-          }
+        if (_cameraTriggerInTurnAroundFact.rawValue().toBool()) {
+            _cameraShots = qCeil(_complexDistance / triggerDistance);
         } else {
-          bool waitingForTriggerStop = false;
-          QGeoCoordinate distanceStartCoord;
-          QGeoCoordinate distanceEndCoord;
-          for (const MissionItem *missionItem : _loadedMissionItems) {
-            if (missionItem->command() == MAV_CMD_NAV_WAYPOINT) {
-              if (waitingForTriggerStop) {
-                distanceEndCoord = QGeoCoordinate(missionItem->param5(),
-                                                  missionItem->param6());
-              } else {
-                distanceStartCoord = QGeoCoordinate(missionItem->param5(),
-                                                    missionItem->param6());
-              }
-            } else if (missionItem->command() ==
-                       MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
-              if (missionItem->param1() > 0) {
-                // Trigger start
-                waitingForTriggerStop = true;
-              } else {
-                // Trigger stop
-                waitingForTriggerStop = false;
-                _cameraShots +=
-                    qCeil(distanceEndCoord.distanceTo(distanceStartCoord) /
-                          triggerDistance);
-                distanceStartCoord = QGeoCoordinate();
-                distanceEndCoord = QGeoCoordinate();
-              }
+            _cameraShots = 0;
+
+            if (_loadedMissionItemsParent) {
+                // We have to do it the hard way based on the mission items themselves
+                if (hoverAndCaptureEnabled()) {
+                    // Count the number of camera triggers in the mission items
+                    for (const MissionItem* missionItem: _loadedMissionItems) {
+                        _cameraShots += missionItem->command() == MAV_CMD_IMAGE_START_CAPTURE ? 1 : 0;
+                    }
+                } else {
+                    bool waitingForTriggerStop = false;
+                    QGeoCoordinate distanceStartCoord;
+                    QGeoCoordinate distanceEndCoord;
+                    for (const MissionItem* missionItem: _loadedMissionItems) {
+                        if (missionItem->command() == MAV_CMD_NAV_WAYPOINT) {
+                            if (waitingForTriggerStop) {
+                                distanceEndCoord = QGeoCoordinate(missionItem->param5(), missionItem->param6());
+                            } else {
+                                distanceStartCoord = QGeoCoordinate(missionItem->param5(), missionItem->param6());
+                            }
+                        } else if (missionItem->command() == MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
+                            if (missionItem->param1() > 0) {
+                                // Trigger start
+                                waitingForTriggerStop = true;
+                            } else {
+                                // Trigger stop
+                                waitingForTriggerStop = false;
+                                _cameraShots += qCeil(distanceEndCoord.distanceTo(distanceStartCoord) / triggerDistance);
+                                distanceStartCoord = QGeoCoordinate();
+                                distanceEndCoord = QGeoCoordinate();
+                            }
+                        }
+                    }
+
+                }
+            } else {
+                // We have transects available, calc from those
+                for (const QList<TransectStyleComplexItem::CoordInfo_t>& transect: _transects) {
+                    QGeoCoordinate firstCameraCoord, lastCameraCoord;
+                    if (_hasTurnaround() && !hoverAndCaptureEnabled()) {
+                        firstCameraCoord = transect[1].coord;
+                        lastCameraCoord = transect[transect.count() - 2].coord;
+                    } else {
+                        firstCameraCoord = transect.first().coord;
+                        lastCameraCoord = transect.last().coord;
+                    }
+                    _cameraShots += qCeil(firstCameraCoord.distanceTo(lastCameraCoord) / triggerDistance);
+                }
             }
-          }
         }
-      } else {
-        // We have transects available, calc from those
-        for (const QList<TransectStyleComplexItem::CoordInfo_t> &transect :
-             _transects) {
-          QGeoCoordinate firstCameraCoord, lastCameraCoord;
-          if (_hasTurnaround() && !hoverAndCaptureEnabled()) {
-            firstCameraCoord = transect[1].coord;
-            lastCameraCoord = transect[transect.count() - 2].coord;
-          } else {
-            firstCameraCoord = transect.first().coord;
-            lastCameraCoord = transect.last().coord;
-          }
-          _cameraShots += qCeil(firstCameraCoord.distanceTo(lastCameraCoord) /
-                                triggerDistance);
-        }
-      }
     }
-  }
 
-  emit cameraShotsChanged();
+    emit cameraShotsChanged();
 }
 
-SurveyComplexItem::ReadyForSaveState
-SurveyComplexItem::readyForSaveState(void) const {
-  return TransectStyleComplexItem::readyForSaveState();
+SurveyComplexItem::ReadyForSaveState SurveyComplexItem::readyForSaveState(void) const
+{
+    return TransectStyleComplexItem::readyForSaveState();
 }
 
-void SurveyComplexItem::rotateEntryPoint(void) {
-  if (_entryPoint == EntryLocationLast) {
-    _entryPoint = EntryLocationFirst;
-  } else {
-    _entryPoint++;
-  }
+void SurveyComplexItem::rotateEntryPoint(void)
+{
+    if (_entryPoint == EntryLocationLast) {
+        _entryPoint = EntryLocationFirst;
+    } else {
+        _entryPoint++;
+    }
 
-  _rebuildTransects();
+    _rebuildTransects();
 
-  setDirty(true);
+    setDirty(true);
 }
 
-double SurveyComplexItem::timeBetweenShots(void) {
-  return _vehicleSpeed == 0 ? 0 : triggerDistance() / _vehicleSpeed;
+double SurveyComplexItem::timeBetweenShots(void)
+{
+    return _vehicleSpeed == 0 ? 0 : triggerDistance() / _vehicleSpeed;
 }
 
-double SurveyComplexItem::additionalTimeDelay(void) const {
-  double hoverTime = 0;
+double SurveyComplexItem::additionalTimeDelay (void) const
+{
+    double hoverTime = 0;
 
-  if (hoverAndCaptureEnabled()) {
-    for (const QList<TransectStyleComplexItem::CoordInfo_t> &transect :
-         _transects) {
-      hoverTime += _hoverAndCaptureDelaySeconds * transect.count();
+    if (hoverAndCaptureEnabled()) {
+        for (const QList<TransectStyleComplexItem::CoordInfo_t>& transect: _transects) {
+            hoverTime += _hoverAndCaptureDelaySeconds * transect.count();
+        }
     }
-  }
 
-  return hoverTime;
+    return hoverTime;
 }
 
-void SurveyComplexItem::_updateWizardMode(void) {
-  if (_surveyAreaPolygon.isValid() && !_surveyAreaPolygon.traceMode()) {
-    setWizardMode(false);
-  }
+void SurveyComplexItem::_updateWizardMode(void)
+{
+    if (_surveyAreaPolygon.isValid() && !_surveyAreaPolygon.traceMode()) {
+        setWizardMode(false);
+    }
 }
diff --git a/src/MissionManager/SurveyComplexItem.h b/src/MissionManager/SurveyComplexItem.h
index 3ead3027f527e6c80a91291bb95a899e5d17e24b..78c103a1ab39a7b84a69e5d4ae63bf39014180a5 100644
--- a/src/MissionManager/SurveyComplexItem.h
+++ b/src/MissionManager/SurveyComplexItem.h
@@ -9,186 +9,163 @@
 
 #pragma once
 
+#include "TransectStyleComplexItem.h"
 #include "MissionItem.h"
-#include "QGCLoggingCategory.h"
 #include "SettingsFact.h"
-#include "TransectStyleComplexItem.h"
+#include "QGCLoggingCategory.h"
 
 Q_DECLARE_LOGGING_CATEGORY(SurveyComplexItemLog)
 
 class PlanMasterController;
 
-class SurveyComplexItem : public TransectStyleComplexItem {
-  Q_OBJECT
+class SurveyComplexItem : public TransectStyleComplexItem
+{
+    Q_OBJECT
 
 public:
-  /// @param flyView true: Created for use in the Fly View, false: Created for
-  /// use in the Plan View
-  /// @param kmlOrShpFile Polygon comes from this file, empty for default
-  /// polygon
-  SurveyComplexItem(PlanMasterController *masterController, bool flyView,
-                    const QString &kmlOrShpFile, QObject *parent);
-
-  Q_PROPERTY(Fact *gridAngle READ gridAngle CONSTANT)
-  Q_PROPERTY(Fact *flyAlternateTransects READ flyAlternateTransects CONSTANT)
-  Q_PROPERTY(Fact *splitConcavePolygons READ splitConcavePolygons CONSTANT)
-
-  Fact *gridAngle(void) { return &_gridAngleFact; }
-  Fact *flyAlternateTransects(void) { return &_flyAlternateTransectsFact; }
-  Fact *splitConcavePolygons(void) { return &_splitConcavePolygonsFact; }
-
-  Q_INVOKABLE void rotateEntryPoint(void);
-
-  // Overrides from ComplexMissionItem
-  QString patternName(void) const final { return name; }
-  bool load(const QJsonObject &complexObject, int sequenceNumber,
-            QString &errorString) final;
-  QString mapVisualQML(void) const final {
-    return QStringLiteral("SurveyMapVisual.qml");
-  }
-  QString presetsSettingsGroup(void) { return settingsGroup; }
-  void savePreset(const QString &name);
-  void loadPreset(const QString &name);
-
-  // Overrides from TransectStyleComplexItem
-  void save(QJsonObject &planItems) final;
-  bool specifiesCoordinate(void) const final { return true; }
-  double timeBetweenShots(void) final;
-
-  // Overrides from VisualMissionionItem
-  QString commandDescription(void) const final { return tr("Survey"); }
-  QString commandName(void) const final { return tr("Survey"); }
-  QString abbreviation(void) const final { return tr("S"); }
-  ReadyForSaveState readyForSaveState(void) const final;
-  double additionalTimeDelay(void) const final;
-
-  // Must match json spec for GridEntryLocation
-  enum EntryLocation {
-    EntryLocationFirst,
-    EntryLocationTopLeft = EntryLocationFirst,
-    EntryLocationTopRight,
-    EntryLocationBottomLeft,
-    EntryLocationBottomRight,
-    EntryLocationLast = EntryLocationBottomRight
-  };
-
-  static const QString name;
-
-  static const char *jsonComplexItemTypeValue;
-  static const char *settingsGroup;
-  static const char *gridAngleName;
-  static const char *gridEntryLocationName;
-  static const char *flyAlternateTransectsName;
-  static const char *splitConcavePolygonsName;
-
-  static const char *jsonV3ComplexItemTypeValue;
+    /// @param flyView true: Created for use in the Fly View, false: Created for use in the Plan View
+    /// @param kmlOrShpFile Polygon comes from this file, empty for default polygon
+    SurveyComplexItem(PlanMasterController* masterController, bool flyView, const QString& kmlOrShpFile, QObject* parent);
+
+    Q_PROPERTY(Fact* gridAngle              READ gridAngle              CONSTANT)
+    Q_PROPERTY(Fact* flyAlternateTransects  READ flyAlternateTransects  CONSTANT)
+    Q_PROPERTY(Fact* splitConcavePolygons   READ splitConcavePolygons   CONSTANT)
+
+    Fact* gridAngle             (void) { return &_gridAngleFact; }
+    Fact* flyAlternateTransects (void) { return &_flyAlternateTransectsFact; }
+    Fact* splitConcavePolygons  (void) { return &_splitConcavePolygonsFact; }
+
+    Q_INVOKABLE void rotateEntryPoint(void);
+
+    // Overrides from ComplexMissionItem
+    QString patternName         (void) const final { return name; }
+    bool    load                (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final;
+    QString mapVisualQML        (void) const final { return QStringLiteral("SurveyMapVisual.qml"); }
+    QString presetsSettingsGroup(void) { return settingsGroup; }
+    void    savePreset          (const QString& name);
+    void    loadPreset          (const QString& name);
+
+    // Overrides from TransectStyleComplexItem
+    void    save                (QJsonArray&  planItems) final;
+    bool    specifiesCoordinate (void) const final { return true; }
+    double  timeBetweenShots    (void) final;
+
+    // Overrides from VisualMissionionItem
+    QString             commandDescription  (void) const final { return tr("Survey"); }
+    QString             commandName         (void) const final { return tr("Survey"); }
+    QString             abbreviation        (void) const final { return tr("S"); }
+    ReadyForSaveState   readyForSaveState    (void) const final;
+    double              additionalTimeDelay (void) const final;
+
+    // Must match json spec for GridEntryLocation
+    enum EntryLocation {
+        EntryLocationFirst,
+        EntryLocationTopLeft = EntryLocationFirst,
+        EntryLocationTopRight,
+        EntryLocationBottomLeft,
+        EntryLocationBottomRight,
+        EntryLocationLast = EntryLocationBottomRight
+    };
+
+    static const QString name;
+
+    static const char* jsonComplexItemTypeValue;
+    static const char* settingsGroup;
+    static const char* gridAngleName;
+    static const char* gridEntryLocationName;
+    static const char* flyAlternateTransectsName;
+    static const char* splitConcavePolygonsName;
+
+    static const char* jsonV3ComplexItemTypeValue;
 
 signals:
-  void refly90DegreesChanged(bool refly90Degrees);
+    void refly90DegreesChanged(bool refly90Degrees);
 
 private slots:
-  void _updateWizardMode(void);
+    void _updateWizardMode              (void);
 
-  // Overrides from TransectStyleComplexItem
-  void _rebuildTransectsPhase1(void) final;
-  void _recalcCameraShots(void) final;
+    // Overrides from TransectStyleComplexItem
+    void _rebuildTransectsPhase1        (void) final;
+    void _recalcCameraShots             (void) final;
 
 private:
-  enum CameraTriggerCode {
-    CameraTriggerNone,
-    CameraTriggerOn,
-    CameraTriggerOff,
-    CameraTriggerHoverAndCapture
-  };
-
-  QPointF _rotatePoint(const QPointF &point, const QPointF &origin,
-                       double angle);
-  void _intersectLinesWithRect(const QList<QLineF> &lineList,
-                               const QRectF &boundRect,
-                               QList<QLineF> &resultLines);
-  void _intersectLinesWithPolygon(const QList<QLineF> &lineList,
-                                  const QPolygonF &polygon,
-                                  QList<QLineF> &resultLines);
-  void _adjustLineDirection(const QList<QLineF> &lineList,
-                            QList<QLineF> &resultLines);
-  bool _nextTransectCoord(const QList<QGeoCoordinate> &transectPoints,
-                          int pointIndex, QGeoCoordinate &coord);
-  bool _appendMissionItemsWorker(QList<MissionItem *> &items,
-                                 QObject *missionItemParent, int &seqNum,
-                                 bool hasRefly, bool buildRefly);
-  void _optimizeTransectsForShortestDistance(
-      const QGeoCoordinate &distanceCoord,
-      QList<QList<QGeoCoordinate>> &transects);
-  qreal _ccw(QPointF pt1, QPointF pt2, QPointF pt3);
-  qreal _dp(QPointF pt1, QPointF pt2);
-  void _swapPoints(QList<QPointF> &points, int index1, int index2);
-  void _reverseTransectOrder(QList<QList<QGeoCoordinate>> &transects);
-  void _reverseInternalTransectPoints(QList<QList<QGeoCoordinate>> &transects);
-  void
-  _adjustTransectsToEntryPointLocation(QList<QList<QGeoCoordinate>> &transects);
-  bool _gridAngleIsNorthSouthTransects();
-  double _clampGridAngle90(double gridAngle);
-  bool _imagesEverywhere(void) const;
-  bool _triggerCamera(void) const;
-  bool _hasTurnaround(void) const;
-  double _turnaroundDistance(void) const;
-
-  bool _hoverAndCaptureEnabled(void) const;
-  bool _loadV3(const QJsonObject &complexObject, int sequenceNumber,
-               QString &errorString);
-  bool _loadV4V5(const QJsonObject &complexObject, int sequenceNumber,
-                 QString &errorString, int version, bool forPresets);
-  void _saveWorker(QJsonObject &complexObject);
-  void _rebuildTransectsPhase1Worker(bool refly);
-  void _rebuildTransectsPhase1WorkerSinglePolygon(bool refly);
-  void _rebuildTransectsPhase1WorkerSplitPolygons(bool refly);
-  /// Adds to the _transects array from one polygon
-  void _rebuildTransectsFromPolygon(bool refly, const QPolygonF &polygon,
-                                    const QGeoCoordinate &tangentOrigin,
-                                    const QPointF *const transitionPoint);
-  // Decompose polygon into list of convex sub polygons
-  void _PolygonDecomposeConvex(const QPolygonF &polygon,
-                               QList<QPolygonF> &decomposedPolygons);
-  // return true if vertex a can see vertex b
-  bool _VertexCanSeeOther(const QPolygonF &polygon, const QPointF *vertexA,
-                          const QPointF *vertexB);
-  bool _VertexIsReflex(const QPolygonF &polygon, const QPointF *vertex);
-
-  QMap<QString, FactMetaData *> _metaDataMap;
-
-  SettingsFact _gridAngleFact;
-  SettingsFact _flyAlternateTransectsFact;
-  SettingsFact _splitConcavePolygonsFact;
-  int _entryPoint;
-
-  static const char *_jsonGridAngleKey;
-  static const char *_jsonEntryPointKey;
-  static const char *_jsonFlyAlternateTransectsKey;
-  static const char *_jsonSplitConcavePolygonsKey;
-
-  static const char *_jsonV3GridObjectKey;
-  static const char *_jsonV3GridAltitudeKey;
-  static const char *_jsonV3GridAltitudeRelativeKey;
-  static const char *_jsonV3GridAngleKey;
-  static const char *_jsonV3GridSpacingKey;
-  static const char *_jsonV3EntryPointKey;
-  static const char *_jsonV3TurnaroundDistKey;
-  static const char *_jsonV3CameraTriggerDistanceKey;
-  static const char *_jsonV3CameraTriggerInTurnaroundKey;
-  static const char *_jsonV3HoverAndCaptureKey;
-  static const char *_jsonV3GroundResolutionKey;
-  static const char *_jsonV3FrontalOverlapKey;
-  static const char *_jsonV3SideOverlapKey;
-  static const char *_jsonV3CameraSensorWidthKey;
-  static const char *_jsonV3CameraSensorHeightKey;
-  static const char *_jsonV3CameraResolutionWidthKey;
-  static const char *_jsonV3CameraResolutionHeightKey;
-  static const char *_jsonV3CameraFocalLengthKey;
-  static const char *_jsonV3CameraMinTriggerIntervalKey;
-  static const char *_jsonV3ManualGridKey;
-  static const char *_jsonV3CameraObjectKey;
-  static const char *_jsonV3CameraNameKey;
-  static const char *_jsonV3CameraOrientationLandscapeKey;
-  static const char *_jsonV3FixedValueIsAltitudeKey;
-  static const char *_jsonV3Refly90DegreesKey;
+    enum CameraTriggerCode {
+        CameraTriggerNone,
+        CameraTriggerOn,
+        CameraTriggerOff,
+        CameraTriggerHoverAndCapture
+    };
+
+    QPointF _rotatePoint(const QPointF& point, const QPointF& origin, double angle);
+    void _intersectLinesWithRect(const QList<QLineF>& lineList, const QRectF& boundRect, QList<QLineF>& resultLines);
+    void _intersectLinesWithPolygon(const QList<QLineF>& lineList, const QPolygonF& polygon, QList<QLineF>& resultLines);
+    void _adjustLineDirection(const QList<QLineF>& lineList, QList<QLineF>& resultLines);
+    bool _nextTransectCoord(const QList<QGeoCoordinate>& transectPoints, int pointIndex, QGeoCoordinate& coord);
+    bool _appendMissionItemsWorker(QList<MissionItem*>& items, QObject* missionItemParent, int& seqNum, bool hasRefly, bool buildRefly);
+    void _optimizeTransectsForShortestDistance(const QGeoCoordinate& distanceCoord, QList<QList<QGeoCoordinate>>& transects);
+    qreal _ccw(QPointF pt1, QPointF pt2, QPointF pt3);
+    qreal _dp(QPointF pt1, QPointF pt2);
+    void _swapPoints(QList<QPointF>& points, int index1, int index2);
+    void _reverseTransectOrder(QList<QList<QGeoCoordinate>>& transects);
+    void _reverseInternalTransectPoints(QList<QList<QGeoCoordinate>>& transects);
+    void _adjustTransectsToEntryPointLocation(QList<QList<QGeoCoordinate>>& transects);
+    bool _gridAngleIsNorthSouthTransects();
+    double _clampGridAngle90(double gridAngle);
+    bool _imagesEverywhere(void) const;
+    bool _triggerCamera(void) const;
+    bool _hasTurnaround(void) const;
+    double _turnaroundDistance(void) const;
+
+    bool _hoverAndCaptureEnabled(void) const;
+    bool _loadV3(const QJsonObject& complexObject, int sequenceNumber, QString& errorString);
+    bool _loadV4V5(const QJsonObject& complexObject, int sequenceNumber, QString& errorString, int version, bool forPresets);
+    void _saveWorker(QJsonObject& complexObject);
+    void _rebuildTransectsPhase1Worker(bool refly);
+    void _rebuildTransectsPhase1WorkerSinglePolygon(bool refly);
+    void _rebuildTransectsPhase1WorkerSplitPolygons(bool refly);
+    /// Adds to the _transects array from one polygon
+    void _rebuildTransectsFromPolygon(bool refly, const QPolygonF& polygon, const QGeoCoordinate& tangentOrigin, const QPointF* const transitionPoint);
+    // Decompose polygon into list of convex sub polygons
+    void _PolygonDecomposeConvex(const QPolygonF& polygon, QList<QPolygonF>& decomposedPolygons);
+    // return true if vertex a can see vertex b
+    bool _VertexCanSeeOther(const QPolygonF& polygon, const QPointF* vertexA, const QPointF* vertexB);
+    bool _VertexIsReflex(const QPolygonF& polygon, const QPointF* vertex);
+
+    QMap<QString, FactMetaData*> _metaDataMap;
+
+    SettingsFact    _gridAngleFact;
+    SettingsFact    _flyAlternateTransectsFact;
+    SettingsFact    _splitConcavePolygonsFact;
+    int             _entryPoint;
+
+    static const char* _jsonGridAngleKey;
+    static const char* _jsonEntryPointKey;
+    static const char* _jsonFlyAlternateTransectsKey;
+    static const char* _jsonSplitConcavePolygonsKey;
+
+    static const char* _jsonV3GridObjectKey;
+    static const char* _jsonV3GridAltitudeKey;
+    static const char* _jsonV3GridAltitudeRelativeKey;
+    static const char* _jsonV3GridAngleKey;
+    static const char* _jsonV3GridSpacingKey;
+    static const char* _jsonV3EntryPointKey;
+    static const char* _jsonV3TurnaroundDistKey;
+    static const char* _jsonV3CameraTriggerDistanceKey;
+    static const char* _jsonV3CameraTriggerInTurnaroundKey;
+    static const char* _jsonV3HoverAndCaptureKey;
+    static const char* _jsonV3GroundResolutionKey;
+    static const char* _jsonV3FrontalOverlapKey;
+    static const char* _jsonV3SideOverlapKey;
+    static const char* _jsonV3CameraSensorWidthKey;
+    static const char* _jsonV3CameraSensorHeightKey;
+    static const char* _jsonV3CameraResolutionWidthKey;
+    static const char* _jsonV3CameraResolutionHeightKey;
+    static const char* _jsonV3CameraFocalLengthKey;
+    static const char* _jsonV3CameraMinTriggerIntervalKey;
+    static const char* _jsonV3ManualGridKey;
+    static const char* _jsonV3CameraObjectKey;
+    static const char* _jsonV3CameraNameKey;
+    static const char* _jsonV3CameraOrientationLandscapeKey;
+    static const char* _jsonV3FixedValueIsAltitudeKey;
+    static const char* _jsonV3Refly90DegreesKey;
 };
diff --git a/src/MissionManager/TransectStyleComplexItem.cc b/src/MissionManager/TransectStyleComplexItem.cc
index 504f28d2a4c8b766be7e882f452d26a93ce0b9a9..e85f9497038da3ab7b4d4689fef18a641dc5c1eb 100644
--- a/src/MissionManager/TransectStyleComplexItem.cc
+++ b/src/MissionManager/TransectStyleComplexItem.cc
@@ -171,7 +171,7 @@ void TransectStyleComplexItem::_save(QJsonObject& complexObject)
     innerObject[_jsonVisualTransectPointsKey] = transectPointsJson;
 
     // Save the interal mission items
-    QJsonObject  missionItemsJsonArray;
+    QJsonArray  missionItemsJsonArray;
     QObject* missionItemParent = new QObject();
     QList<MissionItem*> missionItems;
     appendMissionItems(missionItems, missionItemParent);
@@ -242,7 +242,7 @@ bool TransectStyleComplexItem::_load(const QJsonObject& complexObject, bool forP
 
         // Load generated mission items
         _loadedMissionItemsParent = new QObject(this);
-        QJsonObject missionItemsJsonArray = innerObject[_jsonItemsKey].toArray();
+        QJsonArray missionItemsJsonArray = innerObject[_jsonItemsKey].toArray();
         for (const QJsonValue missionItemJson: missionItemsJsonArray) {
             MissionItem* missionItem = new MissionItem(_loadedMissionItemsParent);
             if (!missionItem->load(missionItemJson.toObject(), 0 /* sequenceNumber */, errorString)) {
diff --git a/src/MissionManager/TransectStyleComplexItem.h b/src/MissionManager/TransectStyleComplexItem.h
index d44e4ffc8d39ce2a3d76f7beeead22d379e6d1ec..949c3bf3c4156471ef1e15a67123bb53c4e44e0c 100644
--- a/src/MissionManager/TransectStyleComplexItem.h
+++ b/src/MissionManager/TransectStyleComplexItem.h
@@ -86,7 +86,7 @@ public:
     double  greatestDistanceTo  (const QGeoCoordinate &other) const final;
 
     // Overrides from VisualMissionItem
-    void                save                        (QJsonObject&  planItems) override = 0;
+    void                save                        (QJsonArray&  planItems) override = 0;
     bool                specifiesCoordinate         (void) const override = 0;
     virtual void        appendMissionItems          (QList<MissionItem*>& items, QObject* missionItemParent) final;
     virtual void        applyNewAltitude            (double newAltitude) final;
diff --git a/src/MissionManager/TransectStyleComplexItemTest.h b/src/MissionManager/TransectStyleComplexItemTest.h
index 054b78b755c894f0308bcb937777bacbc8bdbbc4..d430615f7de7c2fe0b2893fd7f9f3d8d27fd9bad 100644
--- a/src/MissionManager/TransectStyleComplexItemTest.h
+++ b/src/MissionManager/TransectStyleComplexItemTest.h
@@ -88,7 +88,7 @@ public:
     bool    load                (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final { Q_UNUSED(complexObject); Q_UNUSED(sequenceNumber); Q_UNUSED(errorString); return false; }
 
     // Overrides from VisualMissionItem
-    void    save                (QJsonObject&  missionItems) final { Q_UNUSED(missionItems); }
+    void    save                (QJsonArray&  missionItems) final { Q_UNUSED(missionItems); }
     bool    specifiesCoordinate (void) const final { return true; }
     double  additionalTimeDelay (void) const final { return 0; }
 
diff --git a/src/MissionManager/VTOLLandingComplexItem.cc b/src/MissionManager/VTOLLandingComplexItem.cc
index 5ff8d850228fc237a7d37069663f42d744ab3871..808ccec96e67b46c87c943af9ca3c7e9651f944a 100644
--- a/src/MissionManager/VTOLLandingComplexItem.cc
+++ b/src/MissionManager/VTOLLandingComplexItem.cc
@@ -57,7 +57,7 @@ VTOLLandingComplexItem::VTOLLandingComplexItem(PlanMasterController* masterContr
     setDirty(false);
 }
 
-void VTOLLandingComplexItem::save(QJsonObject&  missionItems)
+void VTOLLandingComplexItem::save(QJsonArray&  missionItems)
 {
     QJsonObject saveObject = _save();
 
diff --git a/src/MissionManager/VTOLLandingComplexItem.h b/src/MissionManager/VTOLLandingComplexItem.h
index a604524bccc50e659a18e9ebce98e96d3b023341..f5a8afc8f3d4a6ed9ba78d72b29e4d557afd6373 100644
--- a/src/MissionManager/VTOLLandingComplexItem.h
+++ b/src/MissionManager/VTOLLandingComplexItem.h
@@ -35,7 +35,7 @@ public:
     QString mapVisualQML        (void) const final { return QStringLiteral("VTOLLandingPatternMapVisual.qml"); }
 
     // Overrides from VisualMissionItem
-    void                save                        (QJsonObject&  missionItems) final;
+    void                save                        (QJsonArray&  missionItems) final;
 
     static const QString name;
 
diff --git a/src/MissionManager/VisualMissionItem.h b/src/MissionManager/VisualMissionItem.h
index 887a0410d554760efa71a43b3fb2317b1a1ecd5e..df0bac2172ebc25d90341d120aa109dee2b971de 100644
--- a/src/MissionManager/VisualMissionItem.h
+++ b/src/MissionManager/VisualMissionItem.h
@@ -177,7 +177,7 @@ public:
 
     /// Save the item(s) in Json format
     ///     @param missionItems Current set of mission items, new items should be appended to the end
-    virtual void save(QJsonObject&  missionItems) = 0;
+    virtual void save(QJsonArray&  missionItems) = 0;
 
     /// @return The QML resource file which contains the control which visualizes the item on the map.
     virtual QString mapVisualQML(void) const = 0;
diff --git a/src/QtLocationPlugin/QGeoCodeReplyQGC.cpp b/src/QtLocationPlugin/QGeoCodeReplyQGC.cpp
index b81ea9cd09d6d77c73618c3faf94a2d75b0a5cfe..1bf8cd3ed9b2dd728f85596a8019b167d26d2654 100644
--- a/src/QtLocationPlugin/QGeoCodeReplyQGC.cpp
+++ b/src/QtLocationPlugin/QGeoCodeReplyQGC.cpp
@@ -97,7 +97,7 @@ enum QGCGeoCodeType {
 class JasonMonger {
 public:
     JasonMonger();
-    QSet<int> json2QGCGeoCodeType(const QJsonObject &types);
+    QSet<int> json2QGCGeoCodeType(const QJsonArray &types);
 private:
     int _getCode(const QString &key);
     QMap<QString, int> _m;
@@ -145,7 +145,7 @@ int JasonMonger::_getCode(const QString &key) {
     return _m.value(key, GeoCodeTypeUnknown);
 }
 
-QSet<int> JasonMonger::json2QGCGeoCodeType(const QJsonObject &types) {
+QSet<int> JasonMonger::json2QGCGeoCodeType(const QJsonArray &types) {
     QSet<int> result;
     for (int i=0; i<types.size(); ++i) {
         result |= _getCode(types[i].toString());
@@ -204,7 +204,7 @@ void QGeoCodeReplyQGC::networkReplyFinished()
     }
 
     QList<QGeoLocation> locations;
-    QJsonObject results = object.value(QStringLiteral("results")).toArray();
+    QJsonArray results = object.value(QStringLiteral("results")).toArray();
     for (int i=0; i<results.size(); ++i) {
         if (!results[i].isObject())
             continue;
@@ -218,7 +218,7 @@ void QGeoCodeReplyQGC::networkReplyFinished()
 
 
         if (geocode.contains(QStringLiteral("address_components"))) {
-            QJsonObject ac = geocode.value(QStringLiteral("address_components")).toArray();
+            QJsonArray ac = geocode.value(QStringLiteral("address_components")).toArray();
 
             for (int j=0; j<ac.size(); ++j) {
                 if (!ac[j].isObject())
diff --git a/src/Terrain/TerrainQuery.cc b/src/Terrain/TerrainQuery.cc
index 6a5e012867d91631fb68a4240fb3d48e70fca869..ae3f72c1ea90b16809843236df806ad7f3b7e303 100644
--- a/src/Terrain/TerrainQuery.cc
+++ b/src/Terrain/TerrainQuery.cc
@@ -223,7 +223,7 @@ void TerrainAirMapQuery::_requestFailed(void)
 void TerrainAirMapQuery::_parseCoordinateData(const QJsonValue& coordinateJson)
 {
     QList<double> heights;
-    const QJsonObject& dataArray = coordinateJson.toArray();
+    const QJsonArray& dataArray = coordinateJson.toArray();
     for (int i = 0; i < dataArray.count(); i++) {
         heights.append(dataArray[i].toDouble());
     }
@@ -234,8 +234,8 @@ void TerrainAirMapQuery::_parseCoordinateData(const QJsonValue& coordinateJson)
 void TerrainAirMapQuery::_parsePathData(const QJsonValue& pathJson)
 {
     QJsonObject jsonObject =    pathJson.toArray()[0].toObject();
-    QJsonObject stepArray =      jsonObject["step"].toArray();
-    QJsonObject profileArray =   jsonObject["profile"].toArray();
+    QJsonArray stepArray =      jsonObject["step"].toArray();
+    QJsonArray profileArray =   jsonObject["profile"].toArray();
 
     double latStep = stepArray[0].toDouble();
     double lonStep = stepArray[1].toDouble();
@@ -258,10 +258,10 @@ void TerrainAirMapQuery::_parseCarpetData(const QJsonValue& carpetJson)
 
     QList<QList<double>> carpet;
     if (!_carpetStatsOnly) {
-        QJsonObject carpetArray =   jsonObject["carpet"].toArray();
+        QJsonArray carpetArray =   jsonObject["carpet"].toArray();
 
         for (int i=0; i<carpetArray.count(); i++) {
-            QJsonObject rowArray = carpetArray[i].toArray();
+            QJsonArray rowArray = carpetArray[i].toArray();
             carpet.append(QList<double>());
 
             for (int j=0; j<rowArray.count(); j++) {
diff --git a/src/TerrainTile.cc b/src/TerrainTile.cc
index c415c75ec2ad806741744d7855f3b54c87b568be..df31eacc543b7b4cdc2af2bd4bfe63768c7957af 100644
--- a/src/TerrainTile.cc
+++ b/src/TerrainTile.cc
@@ -229,8 +229,8 @@ QByteArray TerrainTile::serialize(QByteArray input)
         QByteArray emptyArray;
         return emptyArray;
     }
-    const QJsonObject& swArray = boundsObject[_jsonSouthWestKey].toArray();
-    const QJsonObject& neArray = boundsObject[_jsonNorthEastKey].toArray();
+    const QJsonArray& swArray = boundsObject[_jsonSouthWestKey].toArray();
+    const QJsonArray& neArray = boundsObject[_jsonNorthEastKey].toArray();
     if (swArray.count() < 2 || neArray.count() < 2 ) {
         qCDebug(TerrainTileLog) << "Incomplete bounding location";
         QByteArray emptyArray;
@@ -251,7 +251,7 @@ QByteArray TerrainTile::serialize(QByteArray input)
     }
 
     // Carpet
-    const QJsonObject& carpetArray = dataObject[_jsonCarpetKey].toArray();
+    const QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
     int gridSizeLat = carpetArray.count();
     int gridSizeLon = carpetArray[0].toArray().count();
 
@@ -289,7 +289,7 @@ QByteArray TerrainTile::serialize(QByteArray input)
 
     int valueIndex = 0;
     for (int i = 0; i < gridSizeLat; i++) {
-        const QJsonObject& row = carpetArray[i].toArray();
+        const QJsonArray& row = carpetArray[i].toArray();
         if (row.count() < gridSizeLon) {
             qCDebug(TerrainTileLog) << "Expected row array of " << gridSizeLon << ", instead got " << row.count();
             QByteArray emptyArray;
diff --git a/src/Vehicle/CompInfoParam.cc b/src/Vehicle/CompInfoParam.cc
index f7ffbbf5e47df4bb69785206d3b0f2a1fa886cf7..9b56cd47585117566ada1be36868de83ba829dad 100644
--- a/src/Vehicle/CompInfoParam.cc
+++ b/src/Vehicle/CompInfoParam.cc
@@ -68,7 +68,7 @@ void CompInfoParam::setJson(const QString& metadataJsonFileName, const QString&
         return;
     }
 
-    QJsonObject rgParameters = jsonObj[_jsonParametersKey].toArray();
+    QJsonArray rgParameters = jsonObj[_jsonParametersKey].toArray();
     for (QJsonValue parameterValue: rgParameters) {
         QMap<QString, QString> emptyDefineMap;
 
diff --git a/src/Vehicle/CompInfoVersion.cc b/src/Vehicle/CompInfoVersion.cc
index 06300facf2dfde211c92ccb2f1b1b6a4b9fa8361..f71243e415b95b97026d930a6c16ea646e2a0610 100644
--- a/src/Vehicle/CompInfoVersion.cc
+++ b/src/Vehicle/CompInfoVersion.cc
@@ -58,7 +58,7 @@ void CompInfoVersion::setJson(const QString& metadataJsonFileName, const QString
         return;
     }
 
-    QJsonObject rgSupportedTypes = jsonObj[_jsonSupportedCompMetadataTypesKey].toArray();
+    QJsonArray rgSupportedTypes = jsonObj[_jsonSupportedCompMetadataTypesKey].toArray();
     for (QJsonValue typeValue: rgSupportedTypes) {
         _supportedTypes.append(static_cast<COMP_METADATA_TYPE>(typeValue.toInt()));
     }
diff --git a/src/VehicleSetup/FirmwareUpgradeController.cc b/src/VehicleSetup/FirmwareUpgradeController.cc
index c628e4e8058620b1f85a459253be7c00c57cc5fb..5874560a661fd902369951369dfd373a48377845 100644
--- a/src/VehicleSetup/FirmwareUpgradeController.cc
+++ b/src/VehicleSetup/FirmwareUpgradeController.cc
@@ -877,7 +877,7 @@ void FirmwareUpgradeController::_px4ReleasesGithubDownloadComplete(QString /*rem
             qCWarning(FirmwareUpgradeLog) <<  "px4 releases json document is not an array" << localFile;
             return;
         }
-        QJsonObject releases = doc.array();
+        QJsonArray releases = doc.array();
 
         // The first release marked prerelease=false is stable
         // The first release marked prerelease=true is beta
@@ -941,7 +941,7 @@ void FirmwareUpgradeController::_ardupilotManifestDownloadComplete(QString remot
         }
 
         QJsonObject json =          doc.object();
-        QJsonObject  rgFirmware =    json[_manifestFirmwareJsonKey].toArray();
+        QJsonArray  rgFirmware =    json[_manifestFirmwareJsonKey].toArray();
 
         for (int i=0; i<rgFirmware.count(); i++) {
             const QJsonObject& firmwareJson = rgFirmware[i].toObject();
@@ -966,12 +966,12 @@ void FirmwareUpgradeController::_ardupilotManifestDownloadComplete(QString remot
                 firmwareInfo.version =              firmwareJson[_manifestMavFirmwareVersionJsonKey].toString();
                 firmwareInfo.chibios =              format == QStringLiteral("apj");                firmwareInfo.fmuv2 =                platform.contains(QStringLiteral("fmuv2"));
 
-                QJsonObject bootloaderArray = firmwareJson[_manifestBootloaderStrJsonKey].toArray();
+                QJsonArray bootloaderArray = firmwareJson[_manifestBootloaderStrJsonKey].toArray();
                 for (int j=0; j<bootloaderArray.count(); j++) {
                     firmwareInfo.rgBootloaderPortString.append(bootloaderArray[j].toString());
                 }
 
-                QJsonObject usbidArray = firmwareJson[_manifestUSBIDJsonKey].toArray();
+                QJsonArray usbidArray = firmwareJson[_manifestUSBIDJsonKey].toArray();
                 for (int j=0; j<usbidArray.count(); j++) {
                     QStringList vidpid = usbidArray[j].toString().split('/');
                     QString vid = vidpid[0];
diff --git a/src/comm/QGCSerialPortInfo.cc b/src/comm/QGCSerialPortInfo.cc
index abe35af7a51badce3bb26bab9872b91523af3e18..94acb81f2bc44fda4721c8082261fe954cc734a4 100644
--- a/src/comm/QGCSerialPortInfo.cc
+++ b/src/comm/QGCSerialPortInfo.cc
@@ -110,7 +110,7 @@ void QGCSerialPortInfo::_loadJsonData(void)
         { _jsonNameKey,         QJsonValue::String, true },
     };
 
-    QJsonObject rgBoardInfo = json[_jsonBoardInfoKey].toArray();
+    QJsonArray rgBoardInfo = json[_jsonBoardInfoKey].toArray();
     for (int i=0; i<rgBoardInfo.count(); i++) {
         const QJsonValue& jsonValue = rgBoardInfo[i];
         if (!jsonValue.isObject()) {
@@ -146,7 +146,7 @@ void QGCSerialPortInfo::_loadJsonData(void)
         { _jsonAndroidOnlyKey,  QJsonValue::Bool,   false },
     };
 
-    QJsonObject rgBoardFallback = json[_jsonBoardDescriptionFallbackKey].toArray();
+    QJsonArray rgBoardFallback = json[_jsonBoardDescriptionFallbackKey].toArray();
     for (int i=0; i<rgBoardFallback.count(); i++) {
         const QJsonValue& jsonValue = rgBoardFallback[i];
         if (!jsonValue.isObject()) {