Commit e5b570c5 authored by Valentin Platzgummer's avatar Valentin Platzgummer

temp, QVariant compile error

parent 6485d280
......@@ -37,7 +37,7 @@ FactGroup::FactGroup(int updateRateMsecs, QObject* parent, bool ignoreCamelCase)
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
}
void FactGroup::_loadFromJsonArray(const QJsonArray jsonArray)
void FactGroup::_loadFromJsonArray(const QJsonObject jsonArray)
{
QMap<QString, QString> defineMap;
_nameToFactMetaDataMap = FactMetaData::createMapFromJsonArray(jsonArray, defineMap, this);
......
......@@ -64,7 +64,7 @@ protected slots:
protected:
void _addFact (Fact* fact, const QString& name);
void _addFactGroup (FactGroup* factGroup, const QString& name);
void _loadFromJsonArray (const QJsonArray jsonArray);
void _loadFromJsonArray (const QJsonObject jsonArray);
void _setTelemetryAvailable (bool telemetryAvailable);
int _updateRateMSecs; ///< Update rate for Fact::valueChanged signals, 0: immediate update
......
......@@ -1448,7 +1448,7 @@ QMap<QString, FactMetaData*> FactMetaData::createMapFromJsonFile(const QString&
return metaDataMap;
}
QJsonArray factArray;
QJsonObject 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 QJsonArray jsonArray, QMap<QString, QString>& defineMap, QObject* metaDataParent)
QMap<QString, FactMetaData*> FactMetaData::createMapFromJsonArray(const QJsonObject 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 QJsonArray& rgValueDescription = jsonObject[_enumValuesArrayJsonKey].toArray();
const QJsonObject& 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 QJsonArray& rgValueDescription = jsonObject[_enumBitmaskArrayJsonKey].toArray();
const QJsonObject& 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);
......
......@@ -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 QJsonArray jsonArray, DefineMap_t& defineMap, QObject* metaDataParent);
static QMap<QString, FactMetaData*> createMapFromJsonArray(const QJsonObject jsonArray, DefineMap_t& defineMap, QObject* metaDataParent);
static FactMetaData* createFromJsonObject(const QJsonObject& json, QMap<QString, QString>& defineMap, QObject* metaDataParent);
......
......@@ -8,32 +8,33 @@
****************************************************************************/
#include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#include "QmlObjectListModel.h"
#include "MissionCommandList.h"
#include "FactMetaData.h"
#include "MissionCommandList.h"
#include "QGCApplication.h"
#include "QGCQGeoCoordinate.h"
#include "QmlObjectListModel.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";
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)
{
bool JsonHelper::validateRequiredKeys(const QJsonObject &jsonObject,
const QStringList &keys,
QString &errorString) {
QString missingKeys;
foreach(const QString& key, keys) {
foreach (const QString &key, keys) {
if (!jsonObject.contains(key)) {
if (!missingKeys.isEmpty()) {
missingKeys += QStringLiteral(", ");
......@@ -43,42 +44,48 @@ bool JsonHelper::validateRequiredKeys(const QJsonObject& jsonObject, const QStri
}
if (missingKeys.count() != 0) {
errorString = QObject::tr("The following required keys are missing: %1").arg(missingKeys);
errorString = QObject::tr("The following required keys are missing: %1")
.arg(missingKeys);
return false;
}
return true;
}
bool JsonHelper::_loadGeoCoordinate(const QJsonValue& jsonValue,
bool JsonHelper::_loadGeoCoordinate(const QJsonValue &jsonValue,
bool altitudeRequired,
QGeoCoordinate& coordinate,
QString& errorString,
bool geoJsonFormat)
{
QGeoCoordinate &coordinate,
QString &errorString, bool geoJsonFormat) {
if (!jsonValue.isArray()) {
errorString = QObject::tr("value for coordinate is not array");
return false;
}
QJsonArray coordinateArray = jsonValue.toArray();
QJsonObject coordinateArray = jsonValue.toArray();
int requiredCount = altitudeRequired ? 3 : 2;
if (coordinateArray.count() != requiredCount) {
errorString = QObject::tr("Coordinate array must contain %1 values").arg(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());
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());
coordinate = QGeoCoordinate(coordinateArray[1].toDouble(),
coordinateArray[0].toDouble());
} else {
coordinate = QGeoCoordinate(possibleNaNJsonValue(coordinateArray[0]), possibleNaNJsonValue(coordinateArray[1]));
coordinate = QGeoCoordinate(possibleNaNJsonValue(coordinateArray[0]),
possibleNaNJsonValue(coordinateArray[1]));
}
if (altitudeRequired) {
coordinate.setAltitude(possibleNaNJsonValue(coordinateArray[2]));
......@@ -87,12 +94,10 @@ bool JsonHelper::_loadGeoCoordinate(const QJsonValue& jsonValue,
return true;
}
void JsonHelper::_saveGeoCoordinate(const QGeoCoordinate& coordinate,
bool writeAltitude,
QJsonValue& jsonValue,
bool geoJsonFormat)
{
QJsonArray coordinateArray;
void JsonHelper::_saveGeoCoordinate(const QGeoCoordinate &coordinate,
bool writeAltitude, QJsonValue &jsonValue,
bool geoJsonFormat) {
QJsonObject coordinateArray;
if (geoJsonFormat) {
coordinateArray << coordinate.longitude() << coordinate.latitude();
......@@ -106,49 +111,54 @@ void JsonHelper::_saveGeoCoordinate(const QGeoCoordinate& coordinate,
jsonValue = QJsonValue(coordinateArray);
}
bool JsonHelper::loadGeoCoordinate(const QJsonValue& jsonValue,
bool JsonHelper::loadGeoCoordinate(const QJsonValue &jsonValue,
bool altitudeRequired,
QGeoCoordinate& coordinate,
QString& errorString,
bool geoJsonFormat)
{
return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate, errorString, geoJsonFormat);
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 JsonHelper::loadGeoJsonCoordinate(const QJsonValue &jsonValue,
bool altitudeRequired,
QGeoCoordinate& coordinate,
QString& errorString)
{
return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate, errorString, true /* geoJsonFormat */);
QGeoCoordinate &coordinate,
QString &errorString) {
return _loadGeoCoordinate(jsonValue, altitudeRequired, coordinate,
errorString, true /* geoJsonFormat */);
}
void JsonHelper::saveGeoJsonCoordinate(const QGeoCoordinate& coordinate,
void JsonHelper::saveGeoJsonCoordinate(const QGeoCoordinate &coordinate,
bool writeAltitude,
QJsonValue& jsonValue)
{
_saveGeoCoordinate(coordinate, writeAltitude, jsonValue, true /* geoJsonFormat */);
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++) {
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) {
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]));
errorString =
QObject::tr("Incorrect value type - key:type:expected %1:%2:%3")
.arg(valueKey)
.arg(_jsonValueTypeToString(jsonValue.type()))
.arg(_jsonValueTypeToString(types[i]));
return false;
}
}
......@@ -157,8 +167,8 @@ bool JsonHelper::validateKeyTypes(const QJsonObject& jsonObject, const QStringLi
return true;
}
bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QString& errorString)
{
bool JsonHelper::isJsonFile(const QByteArray &bytes, QJsonDocument &jsonDoc,
QString &errorString) {
QJsonParseError parseError;
jsonDoc = QJsonDocument::fromJson(bytes, &parseError);
......@@ -168,17 +178,20 @@ bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QSt
} 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());
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)
{
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());
errorString = tr("File open failed: file:error %1 %2")
.arg(jsonFile.fileName())
.arg(jsonFile.errorString());
return false;
}
QByteArray jsonBytes = jsonFile.readAll();
......@@ -187,17 +200,16 @@ bool JsonHelper::isJsonFile(const QString& fileName, QJsonDocument& jsonDoc, QSt
return isJsonFile(jsonBytes, jsonDoc, errorString);
}
bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject& jsonObject,
const QString& expectedFileType,
bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject &jsonObject,
const QString &expectedFileType,
int minSupportedVersion,
int maxSupportedVersion,
int& version,
QString& errorString)
{
int &version,
QString &errorString) {
// Validate required keys
QList<JsonHelper::KeyValidateInfo> requiredKeys = {
{ jsonFileTypeKey, QJsonValue::String, true },
{ jsonVersionKey, QJsonValue::Double, true },
{jsonFileTypeKey, QJsonValue::String, true},
{jsonVersionKey, QJsonValue::Double, true},
};
if (!JsonHelper::validateKeys(jsonObject, requiredKeys, errorString)) {
return false;
......@@ -206,44 +218,51 @@ bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject& jsonObject,
// 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);
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);
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);
errorString =
QObject::tr(
"File version %1 is newer than current supported version %2")
.arg(version)
.arg(maxSupportedVersion);
return false;
}
return true;
}
bool JsonHelper::validateExternalQGCJsonFile(const QJsonObject& jsonObject,
const QString& expectedFileType,
bool JsonHelper::validateExternalQGCJsonFile(const QJsonObject &jsonObject,
const QString &expectedFileType,
int minSupportedVersion,
int maxSupportedVersion,
int& version,
QString& errorString)
{
int &version,
QString &errorString) {
// Validate required keys
QList<JsonHelper::KeyValidateInfo> requiredKeys = {
{ jsonGroundStationKey, QJsonValue::String, true },
{jsonGroundStationKey, QJsonValue::String, true},
};
if (!JsonHelper::validateKeys(jsonObject, requiredKeys, errorString)) {
return false;
}
return validateInternalQGCJsonFile(jsonObject, expectedFileType, minSupportedVersion, maxSupportedVersion, version, errorString);
return validateInternalQGCJsonFile(jsonObject, expectedFileType,
minSupportedVersion, maxSupportedVersion,
version, errorString);
}
QStringList JsonHelper::_addDefaultLocKeys(QJsonObject& jsonObject)
{
QStringList JsonHelper::_addDefaultLocKeys(QJsonObject &jsonObject) {
QString translateKeys;
QString fileType = jsonObject[jsonFileTypeKey].toString();
if (!fileType.isEmpty()) {
......@@ -262,7 +281,8 @@ QStringList JsonHelper::_addDefaultLocKeys(QJsonObject& jsonObject)
translateKeys = jsonObject[_translateKeysKey].toString();
} else {
translateKeys = "shortDescription,longDescription,enumStrings";
jsonObject[_translateKeysKey] = "shortDescription,longDescription,enumStrings";
jsonObject[_translateKeysKey] =
"shortDescription,longDescription,enumStrings";
}
if (!jsonObject.contains(_arrayIDKeysKey)) {
jsonObject[_arrayIDKeysKey] = "name";
......@@ -272,9 +292,10 @@ QStringList JsonHelper::_addDefaultLocKeys(QJsonObject& jsonObject)
return translateKeys.split(",");
}
QJsonObject JsonHelper::_translateObject(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys)
{
for (const QString& key: jsonObject.keys()) {
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)) {
......@@ -282,56 +303,67 @@ QJsonObject JsonHelper::_translateObject(QJsonObject& jsonObject, const QString&
QString disambiguationPrefix("#loc.disambiguation#");
if (locString.startsWith(disambiguationPrefix)) {
locString = locString.right(locString.length() - disambiguationPrefix.length());
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);
locString = locString.right(locString.length() -
disambiguation.length() - 1);
}
}
QString xlatString = qgcApp()->qgcJSONTranslator().translate(translateContext.toUtf8().constData(), locString.toUtf8().constData(), disambiguation.toUtf8().constData());
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);
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);
jsonObject[key] =
_translateObject(childJsonObject, translateContext, translateKeys);
}
}
return jsonObject;
}
QJsonArray JsonHelper::_translateArray(QJsonArray& jsonArray, const QString& translateContext, const QStringList& translateKeys)
{
for (int i=0; i<jsonArray.count(); i++) {
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);
jsonArray[i] =
_translateObject(childJsonObject, translateContext, translateKeys);
}
return jsonArray;
}
QJsonObject JsonHelper::_translateRoot(QJsonObject& jsonObject, const QString& translateContext, const QStringList& 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,
QJsonObject JsonHelper::openInternalQGCJsonFile(const QString &jsonFilename,
const QString &expectedFileType,
int minSupportedVersion,
int maxSupportedVersion,
int &version,
QString& errorString)
{
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());
errorString = tr("Unable to open file: '%1', error: %2")
.arg(jsonFilename)
.arg(jsonFile.errorString());
return QJsonObject();
}
......@@ -340,7 +372,10 @@ QJsonObject JsonHelper::openInternalQGCJsonFile(const QString& jsonFilename,
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);
errorString = tr("Unable to parse json file: %1 error: %2 offset: %3")
.arg(jsonFilename)
.arg(jsonParseError.errorString())
.arg(jsonParseError.offset);
return QJsonObject();
}
......@@ -350,7 +385,9 @@ QJsonObject JsonHelper::openInternalQGCJsonFile(const QString& jsonFilename,
}
QJsonObject jsonObject = doc.object();
bool success = validateInternalQGCJsonFile(jsonObject, expectedFileType, minSupportedVersion, maxSupportedVersion, version, errorString);
bool success = validateInternalQGCJsonFile(
jsonObject, expectedFileType, minSupportedVersion, maxSupportedVersion,
version, errorString);
if (!success) {
errorString = tr("Json file: '%1'. %2").arg(jsonFilename).arg(errorString);
return QJsonObject();
......@@ -361,31 +398,29 @@ QJsonObject JsonHelper::openInternalQGCJsonFile(const QString& jsonFilename,
return _translateRoot(jsonObject, context, translateKeys);
}
void JsonHelper::saveQGCJsonFileHeader(QJsonObject& jsonObject,
const QString& fileType,
int 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 JsonHelper::loadGeoCoordinateArray(const QJsonValue &jsonValue,
bool altitudeRequired,
QVariantList& rgVarPoints,
QString& errorString)
{
QVariantList &rgVarPoints,
QString &errorString) {
if (!jsonValue.isArray()) {
errorString = QObject::tr("value for coordinate array is not array");
return false;
}
QJsonArray rgJsonPoints = jsonValue.toArray();
QJsonObject rgJsonPoints = jsonValue.toArray();
rgVarPoints.clear();
for (int i=0; i<rgJsonPoints.count(); i++) {
for (int i = 0; i < rgJsonPoints.count(); i++) {
QGeoCoordinate coordinate;
if (!JsonHelper::loadGeoCoordinate(rgJsonPoints[i], altitudeRequired, coordinate, errorString)) {
if (!JsonHelper::loadGeoCoordinate(rgJsonPoints[i], altitudeRequired,
coordinate, errorString)) {
return false;
}
rgVarPoints.append(QVariant::fromValue(coordinate));
......@@ -394,60 +429,60 @@ bool JsonHelper::loadGeoCoordinateArray(const QJsonValue& jsonValue,
return true;
}
bool JsonHelper::loadGeoCoordinateArray(const QJsonValue& jsonValue,
bool JsonHelper::loadGeoCoordinateArray(const QJsonValue &jsonValue,
bool altitudeRequired,
QList<QGeoCoordinate>& rgPoints,
QString& errorString)
{
QList<QGeoCoordinate> &rgPoints,
QString &errorString) {
QVariantList rgVarPoints;
if (!loadGeoCoordinateArray(jsonValue, altitudeRequired, rgVarPoints, errorString)) {
if (!loadGeoCoordinateArray(jsonValue, altitudeRequired, rgVarPoints,
errorString)) {
return false;
}
rgPoints.clear();
for (int i=0; i<rgVarPoints.count(); i++) {
for (int i = 0; i < rgVarPoints.count(); i++) {
rgPoints.append(rgVarPoints[i].value<QGeoCoordinate>());
}
return true;
}
void JsonHelper::saveGeoCoordinateArray(const QVariantList& rgVarPoints,
void JsonHelper::saveGeoCoordinateArray(const QVariantList &rgVarPoints,
bool writeAltitude,
QJsonValue& jsonValue)
{
QJsonArray rgJsonPoints;
QJsonValue &jsonValue) {
QJsonObject rgJsonPoints;
// Add all points to the array
for (int i=0; i<rgVarPoints.count(); i++) {
for (int i = 0; i < rgVarPoints.count(); i++) {
QJsonValue jsonPoint;
JsonHelper::saveGeoCoordinate(rgVarPoints[i].value<QGeoCoordinate>(), writeAltitude, jsonPoint);
JsonHelper::saveGeoCoordinate(rgVarPoints[i].value<QGeoCoordinate>(),
writeAltitude, jsonPoint);
rgJsonPoints.append(jsonPoint);
}
jsonValue = rgJsonPoints;
}
void JsonHelper::saveGeoCoordinateArray(const QList<QGeoCoordinate>& rgPoints,
void JsonHelper::saveGeoCoordinateArray(const QList<QGeoCoordinate> &rgPoints,
bool writeAltitude,
QJsonValue& jsonValue)
{
QJsonValue &jsonValue) {
QVariantList rgVarPoints;
for (int i=0; i<rgPoints.count(); i++) {
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)
{
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++) {
for (int i = 0; i < keyInfo.count(); i++) {
if (keyInfo[i].required) {
keyList.append(keyInfo[i].key);
}
......@@ -457,29 +492,26 @@ bool JsonHelper::validateKeys(const QJsonObject& jsonObject, const QList<JsonHel
}
keyList.clear();
for (int i=0; i<keyInfo.count(); i++) {
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)
{
QString JsonHelper::_jsonValueTypeToString(QJsonValue::Type type) {
const struct {
QJsonValue::Type type;
const char* string;
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++) {
{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;
}
......@@ -488,13 +520,15 @@ QString JsonHelper::_jsonValueTypeToString(QJsonValue::Type type)
return QObject::tr("Unknown type: %1").arg(type);
}
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];
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];
QGeoCoordinate pointCoord;
if (!JsonHelper::loadGeoCoordinate(pointValue, false /* altitudeRequired */, pointCoord, errorString, true)) {
if (!JsonHelper::loadGeoCoordinate(pointValue, false /* altitudeRequired */,
pointCoord, errorString, true)) {
list.clearAndDeleteContents();
return false;
}
......@@ -504,10 +538,10 @@ bool JsonHelper::loadPolygon(const QJsonArray& polygonArray, QmlObjectListModel&
return true;
}
void JsonHelper::savePolygon(QmlObjectListModel& list, QJsonArray& polygonArray)
{
for (int i=0; i<list.count(); i++) {
QGeoCoordinate vertex = list.value<QGCQGeoCoordinate*>(i)->coordinate();
void JsonHelper::savePolygon(QmlObjectListModel &list,
QJsonObject &polygonArray) {
for (int i = 0; i < list.count(); i++) {
QGeoCoordinate vertex = list.value<QGCQGeoCoordinate *>(i)->coordinate();
QJsonValue jsonValue;
JsonHelper::saveGeoCoordinate(vertex, false /* writeAltitude */, jsonValue);
......@@ -515,8 +549,7 @@ void JsonHelper::savePolygon(QmlObjectListModel& list, QJsonArray& polygonArray)
}
}
double JsonHelper::possibleNaNJsonValue(const QJsonValue& value)
{
double JsonHelper::possibleNaNJsonValue(const QJsonValue &value) {
if (value.type() == QJsonValue::Null) {
return std::numeric_limits<double>::quiet_NaN();
} else {
......
......@@ -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,164 +21,193 @@ class QmlObjectListModel;
/// @brief Json manipulation helper class.
/// Primarily used for parsing and processing Fact metadata.
class 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
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
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
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, ...):
/// 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
/// 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
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
QString &errorString); ///< returned error string if validation fails
/// Validates the standard parts of a internal QGC json file (FactMetaData, ...):
/// 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
/// 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
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
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
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
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
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
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
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);
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
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
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
static void saveGeoCoordinate(
const QGeoCoordinate &coordinate, ///< QGeoCoordinate to save
bool writeAltitude, ///< true: write altitude to json
QJsonValue& jsonValue); ///< json value to save to
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
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
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
static void saveGeoJsonCoordinate(
const QGeoCoordinate &coordinate, ///< QGeoCoordinate to save
bool writeAltitude, ///< true: write altitude to json
QJsonValue& jsonValue); ///< json value to save to
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
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
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
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
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
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
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
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
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 double possibleNaNJsonValue(const QJsonValue &value);
static const char* jsonVersionKey;
static const char* jsonGroundStationKey;
static const char* jsonGroundStationValue;
static const char* jsonFileTypeKey;
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,
static bool _loadGeoCoordinate(const QJsonValue &jsonValue,
bool altitudeRequired,
QGeoCoordinate& coordinate,
QString& errorString,
bool geoJsonFormat);
static void _saveGeoCoordinate(const QGeoCoordinate& coordinate,
bool writeAltitude,
QJsonValue& jsonValue,
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;
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;
};
......@@ -4,12 +4,17 @@
#include "geometry/SafeArea.h"
#include "geometry/snake.h"
#include "JsonHelper.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "QGCQGeoCoordinate.h"
QGC_LOGGING_CATEGORY(AreaDataLog, "AreaDataLog")
const char *originJsonKey = "Origin";
const char *areaListJsonKey = "AreaList";
const char *initializedJsonKey = "Initialized";
AreaData::AreaData(QObject *parent) : QObject(parent) {}
AreaData::~AreaData() {}
......@@ -270,6 +275,41 @@ bool AreaData::operator!=(const AreaData &other) const {
return !(*this == other);
}
bool AreaData::load(const QJsonObject &obj, QString &guiErrorString) {
qWarning() << "AreaData::load impl. missing";
return true;
}
bool AreaData::save(QJsonObject &obj) const {
// QJsonObject temp;
// QJsonValue jsonOrigin;
// JsonHelper::saveGeoCoordinate(_origin, true, jsonOrigin);
// temp[originJsonKey] = jsonOrigin;
// temp[initializedJsonKey] = _initialized;
// QJsonObject jsonAreaList;
// for (int i = 0; i < _areaList.count(); ++i) {
// auto const &qobj = _areaList[i];
// auto const &area = qobject_cast<const GeoArea *>(qobj);
// QJsonObject jsonArea;
// if (area->saveToJson(jsonArea)) {
// QJsonObject jsonObj;
// jsonObj[area->objectName()] = jsonArea;
// jsonAreaList.append(jsonObj);
// } else {
// qDebug(AreaListLog) << "save(): not able to save area: "
// << area->objectName();
// _processError(tr("Not able to save area: ") + area->objectName());
// return false;
// }
// }
// temp[areaListJsonKey] = jsonAreaList;
// obj = std::move(temp);
return true;
}
void AreaData::_setOrigin(const QGeoCoordinate &origin) {
if (this->_origin != origin) {
this->_origin = origin;
......
#pragma once
#include <QGeoCoordinate>
#include <QJsonObject>
#include <QObject>
#include <QString>
#include "QmlObjectListModel.h"
......@@ -72,6 +74,9 @@ public:
bool operator==(const AreaData &other) const;
bool operator!=(const AreaData &other) const;
bool load(const QJsonObject &obj, QString &guiErrorString);
bool save(QJsonObject &obj) const;
QString errorString() const; // Contains a message about the last error.
bool showErrorMessages() const;
......
#include "CircularGenerator.h"
#include "JsonHelper.h"
#include "QGCLoggingCategory.h"
#include "SettingsFact.h"
......@@ -29,9 +30,7 @@ const char *CircularGenerator::settingsGroup = "CircularGenerator";
const char *CircularGenerator::distanceName = "TransectDistance";
const char *CircularGenerator::deltaAlphaName = "DeltaAlpha";
const char *CircularGenerator::minLengthName = "MinLength";
const char *CircularGenerator::refPointLatitudeName = "ReferencePointLat";
const char *CircularGenerator::refPointLongitudeName = "ReferencePointLong";
const char *CircularGenerator::refPointAltitudeName = "ReferencePointAlt";
const char *CircularGenerator::refPointName = "ReferencePoint";
CircularGenerator::CircularGenerator(QObject *parent)
: CircularGenerator(nullptr, parent) {}
......@@ -184,6 +183,55 @@ void CircularGenerator::setReference(const QGeoCoordinate &reference) {
}
}
bool CircularGenerator::save(QJsonObject &obj) const {
// QJsonObject temp;
// bool ok = false;
// auto variant = _distance.rawValue();
// auto val = variant.toDouble(ok);
// if (!ok) {
// qCDebug(CircularGeneratorLog)
// << "save(): not able to save distance. Not a double: "
// << variant.typeName();
// return false;
// } else {
// temp[distanceName] = val;
// }
// variant = _deltaAlpha.rawValue();
// val = variant.toDouble(ok);
// if (!ok) {
// qCDebug(CircularGeneratorLog)
// << "save(): not able to save deltaAlpha. Not a double: "
// << variant.typeName();
// return false;
// } else {
// temp[deltaAlphaName] = val;
// }
// variant = _minLength.rawValue();
// val = variant.toDouble(ok);
// if (!ok) {
// qCDebug(CircularGeneratorLog)
// << "save(): not able to save minLength. Not a double: "
// << variant.typeName();
// return false;
// } else {
// temp[minLengthName] = val;
// }
// QJsonObject jsonReference;
// JsonHelper::saveGeoCoordinate(_reference, true, jsonReference);
// temp[refPointName] = jsonReference;
// obj = std::move(temp);
return true;
}
bool CircularGenerator::load(const QJsonObject &obj, QString &guiErrorMessage) {
qWarning() << "CircularGenerator::load() impl. missing";
return true;
}
void CircularGenerator::resetReferenceIfInvalid() {
if (!this->_reference.isValid()) {
resetReference();
......
......@@ -35,13 +35,22 @@ public:
void setReference(const QGeoCoordinate &reference);
//!
//! \brief save Saves the generator.
//! \param obj Json object for saveing.
//! \return Returns true on success, false either.
//!
//! Saves distance, alpha and minLength.
//! \note This methode does not save the data.
//!
virtual bool save(QJsonObject &obj) const override;
virtual bool load(const QJsonObject &obj, QString &guiErrorMessage) override;
static const char *settingsGroup;
static const char *distanceName;
static const char *deltaAlphaName;
static const char *minLengthName;
static const char *refPointLongitudeName;
static const char *refPointLatitudeName;
static const char *refPointAltitudeName;
static const char *refPointName;
signals:
void referenceChanged();
......
#pragma once
#include <QJsonObject>
#include <QObject>
#include <QString>
#include <functional>
#include <memory>
......@@ -27,6 +29,9 @@ public:
virtual QString editorQml() = 0;
virtual QString mapVisualQml() = 0;
virtual bool save(QJsonObject &obj) const = 0;
virtual bool load(const QJsonObject &obj, QString &guiErrorMessage) = 0;
virtual QString name() = 0;
virtual QString abbreviation() = 0;
......
......@@ -149,6 +149,52 @@ bool LinearGenerator::get(Generator &generator) {
}
}
bool LinearGenerator::save(QJsonObject &obj) const {
// QJsonObject temp;
// bool ok = false;
// auto variant = _distance.rawValue();
// auto val = variant.toDouble(ok);
// if (!ok) {
// qCDebug(LinearGeneratorLog)
// << "save(): not able to save distance. Not a double: "
// << variant.typeName();
// return false;
// } else {
// temp[distanceName] = val;
// }
// variant = _alpha.rawValue();
// val = variant.toDouble(ok);
// if (!ok) {
// qCDebug(LinearGeneratorLog)
// << "save(): not able to save alpha. Not a double: "
// << variant.typeName();
// return false;
// } else {
// temp[alphaName] = val;
// }
// variant = _minLength.rawValue();
// val = variant.toDouble(ok);
// if (!ok) {
// qCDebug(LinearGeneratorLog)
// << "save(): not able to save minLength. Not a double: "
// << variant.typeName();
// return false;
// } else {
// temp[minLengthName] = val;
// }
// obj = std::move(temp);
return true;
}
bool LinearGenerator::load(const QJsonObject &obj, QString &guiErrorString) {
qWarning() << "LinearGenerator::load() impl. missing";
return true;
}
Fact *LinearGenerator::distance() { return &_distance; }
Fact *LinearGenerator::alpha() { return &_alpha; }
......
......@@ -27,6 +27,17 @@ public:
virtual bool get(Generator &generator) override;
//!
//! \brief save Saves the generator.
//! \param obj Json object for saveing.
//! \return Returns true on success, false either.
//!
//! Saves distance, alpha and minLength.
//! \note This methode does not save the data.
//!
virtual bool save(QJsonObject &obj) const override;
virtual bool load(const QJsonObject &obj, QString &guiErrorString) override;
Fact *distance();
Fact *alpha();
Fact *minLength();
......
......@@ -33,6 +33,10 @@ const char *MeasurementComplexItem::jsonComplexItemTypeValue =
const char *MeasurementComplexItem::variantName = "Variant";
const char *MeasurementComplexItem::altitudeName = "Altitude";
const QString MeasurementComplexItem::name(tr("Measurement"));
const char *areaDataName = "AreaDataName";
const char *variantNamesName = "VariantNames";
const char *generatorsName = "Generators";
const char *variantsName = "Variants";
MeasurementComplexItem::MeasurementComplexItem(
PlanMasterController *masterController, bool flyView,
......@@ -208,10 +212,7 @@ QString MeasurementComplexItem::mapVisualQML() const {
return QStringLiteral("MeasurementItemMapVisual.qml");
}
void MeasurementComplexItem::save(QJsonArray &planItems) {
qWarning() << "MeasurementComplexItem::save(): area data save missing.";
qWarning() << "MeasurementComplexItem::save(): mission item save missing.";
void MeasurementComplexItem::save(QJsonObject &planItems) {
if (idle()) {
QJsonObject saveObject;
......@@ -221,10 +222,60 @@ void MeasurementComplexItem::save(QJsonArray &planItems) {
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] =
jsonComplexItemTypeValue;
// Variant and altitude.
saveObject[variantName] = double(_variant.rawValue().toUInt());
saveObject[altitudeName] = double(_altitude.rawValue().toUInt());
// Variant names.
QJsonObject jsonVariantNames;
for (auto const &name : _variantNames) {
jsonVariantNames.append(name);
}
saveObject[variantNamesName] = jsonVariantNames;
// AreaData.
// QJsonObject jsonAreaData;
// if (!_pAreaData->save(jsonAreaData)) {
// qCDebug(MeasurementComplexItemLog)
// << "save(): not able to save area data";
// return;
// }
// saveObject[areaDataName] = jsonAreaData;
// Generators.
// QJsonArray generatorArray;
// for (int i = 0; i < _generatorList.size(); ++i) {
// auto const gen = _generatorList[i];
// auto const &name = _generatorNameList[i];
// QJsonObject innerObj;
// if (!gen->save(innerObj)) {
// qCDebug(MeasurementComplexItemLog)
// << "save(): not able to save generator: " << name;
// return;
// } else {
// QJsonObject outerObj;
// outerObj[name] = innerObj;
// generatorArray.append(outerObj);
// }
// }
// saveObject[generatorsName] = generatorArray;
// Route Variants
QJsonObject variantsArray;
for (auto const &route : _variantVector) {
QJsonValue variant;
if (!(route.size() == 0)) {
JsonHelper::saveGeoCoordinateArray(route, true, variant);
} else {
JsonHelper::saveGeoCoordinateArray(_route, true, variant);
}
variantsArray.append(variant);
}
saveObject[variantsName] = variantsArray;
planItems.append(saveObject);
} else {
qCDebug(MeasurementComplexItemLog) << "save(): called while not idle.";
}
}
......
#pragma once
#include <QFutureWatcher>
#include <QJsonArray>
#include <QVector>
#include <memory>
......@@ -84,7 +85,7 @@ public:
virtual void setDirty(bool dirty) override final;
virtual void setCoordinate(const QGeoCoordinate &coordinate) override final;
virtual void setSequenceNumber(int sequenceNumber) override final;
virtual void save(QJsonArray &missionItems) override final;
virtual void save(QJsonObject &missionItems) override final;
virtual double amslEntryAlt(void) const override final;
virtual double amslExitAlt(void) const override final;
virtual double minAMSLAltitude(void) const override final;
......
......@@ -61,7 +61,7 @@ CorridorScanComplexItem::CorridorScanComplexItem(PlanMasterController* masterCon
setDirty(false);
}
void CorridorScanComplexItem::save(QJsonArray& planItems)
void CorridorScanComplexItem::save(QJsonObject& planItems)
{
QJsonObject saveObject;
......
......@@ -37,7 +37,7 @@ public:
// Overrides from TransectStyleComplexItem
QString patternName (void) const final { return name; }
void save (QJsonArray& planItems) final;
void save (QJsonObject& planItems) final;
bool specifiesCoordinate (void) const final;
double timeBetweenShots (void) final;
......
......@@ -81,7 +81,7 @@ void FWLandingPatternTest::_testDirty(void)
void FWLandingPatternTest::_testSaveLoad(void)
{
QJsonArray items;
QJsonObject items;
_fwItem->save(items);
......
......@@ -60,7 +60,7 @@ FixedWingLandingComplexItem::FixedWingLandingComplexItem(PlanMasterController* m
setDirty(false);
}
void FixedWingLandingComplexItem::save(QJsonArray& missionItems)
void FixedWingLandingComplexItem::save(QJsonObject& missionItems)
{
QJsonObject saveObject = _save();
......
......@@ -44,7 +44,7 @@ public:
QString mapVisualQML (void) const final { return QStringLiteral("FWLandingPatternMapVisual.qml"); }
// Overrides from VisualMissionItem
void save (QJsonArray& missionItems) final;
void save (QJsonObject& missionItems) final;
static const QString name;
......
......@@ -152,7 +152,7 @@ bool GeoFenceController::load(const QJsonObject& json, QString& errorString)
return false;
}
QJsonArray jsonPolygonArray = json[_jsonPolygonsKey].toArray();
QJsonObject 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);
}
QJsonArray jsonCircleArray = json[_jsonCirclesKey].toArray();
QJsonObject 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;
QJsonArray jsonPolygonArray;
QJsonObject 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;
QJsonArray jsonCircleArray;
QJsonObject jsonCircleArray;
for (int i=0; i<_circles.count(); i++) {
QJsonObject jsonCircle;
QGCFenceCircle* fenceCircle = _circles.value<QGCFenceCircle*>(i);
......
......@@ -82,7 +82,7 @@ public:
QString mapVisualQML(void) const final { return QStringLiteral("FWLandingPatternMapVisual.qml"); }
// Overrides from VisualMissionItem
void save (QJsonArray& /*missionItems*/) { };
void save (QJsonObject& /*missionItems*/) { };
static const QString name;
......
......@@ -55,7 +55,7 @@ void MissionCommandList::_loadMavCmdInfoJson(const QString& jsonFilename, bool b
}
// Iterate over MissionCommandUIInfo objects
QJsonArray jsonArray = jsonValue.toArray();
QJsonObject jsonArray = jsonValue.toArray();
for(QJsonValue info: jsonArray) {
if (!info.isObject()) {
qWarning() << jsonFilename << "mavCmdArray should contain objects";
......
......@@ -744,7 +744,7 @@ bool MissionController::_loadJsonMissionFileV1(const QJsonObject &json,
// Read complex items
QList<SurveyComplexItem *> surveyItems;
QJsonArray complexArray(json[_jsonComplexItemsKey].toArray());
QJsonObject 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
QJsonArray itemArray(json[_jsonItemsKey].toArray());
QJsonObject 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 QJsonArray rgMissionItems(json[_jsonItemsKey].toArray());
const QJsonObject 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
QJsonArray rgJsonMissionItems;
QJsonObject rgJsonMissionItems;
for (int i = 0; i < _visualItems->count(); i++) {
VisualMissionItem *visualItem =
qobject_cast<VisualMissionItem *>(_visualItems->get(i));
......
......@@ -147,7 +147,7 @@ void MissionItem::save(QJsonObject &json) const {
json[_jsonAutoContinueKey] = autoContinue();
json[_jsonDoJumpIdKey] = _sequenceNumber;
QJsonArray rgParams = {param1(), param2(), param3(), param4(),
QJsonObject rgParams = {param1(), param2(), param3(), param4(),
param5(), param6(), param7()};
json[_jsonParamsKey] = rgParams;
}
......@@ -206,7 +206,7 @@ bool MissionItem::_convertJsonV1ToV2(const QJsonObject &json,
VisualMissionItem::jsonTypeSimpleItemValue;
}
QJsonArray rgParams = {
QJsonObject 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;
}
QJsonArray rgParam = json[_jsonParamsKey].toArray();
QJsonObject 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;
}
QJsonArray rgParams = convertedJson[_jsonParamsKey].toArray();
QJsonObject rgParams = convertedJson[_jsonParamsKey].toArray();
if (rgParams.count() != 7) {
errorString = tr("%1 key must contains 7 values").arg(_jsonParamsKey);
return false;
......
......@@ -342,7 +342,7 @@ void MissionItemTest::_testLoadFromJsonV2(void)
QVERIFY(!errorString.isEmpty());
qDebug() << errorString;
QJsonArray badCoordinateArray;
QJsonObject badCoordinateArray;
badCoordinateArray << -10.0 << -20.0 ;
badObject = jsonObject;
badObject.remove("coordinate");
......@@ -351,7 +351,7 @@ void MissionItemTest::_testLoadFromJsonV2(void)
QVERIFY(!errorString.isEmpty());
qDebug() << errorString;
QJsonArray badCoordinateArray_second;
QJsonObject 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;
QJsonArray badCoordinateArray2;
QJsonObject badCoordinateArray2;
badCoordinateArray2 << 1 << 2;
QJsonArray badCoordinateArray_third;
QJsonObject 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;
QJsonArray rgParam = badObject[MissionItem::_jsonParamsKey].toArray();
QJsonObject 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;
QJsonArray coordinateArray;
QJsonObject 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);
QJsonArray rgParams = { 10, 20, 30, 40 };
QJsonObject 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;
QJsonArray coordinateArray;
QJsonObject 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;
QJsonArray coordinateArray;
QJsonObject 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);
QJsonArray rgParams = { 10, 20, 30, 40 };
QJsonObject 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) {
QJsonArray rgParams = { NAN, NAN, NAN, NAN, NAN, NAN, NAN };
QJsonObject rgParams = { NAN, NAN, NAN, NAN, NAN, NAN, NAN };
jsonObject.insert(MissionItem::_jsonParamsKey, rgParams);
} else {
QJsonArray rgParams = { 10, 20, 30, 40, -10, -20, -30 };
QJsonObject rgParams = { 10, 20, 30, 40, -10, -20, -30 };
jsonObject.insert(MissionItem::_jsonParamsKey, rgParams);
}
......
......@@ -88,7 +88,7 @@ void MissionSettingsItem::setDirty(bool dirty)
}
}
void MissionSettingsItem::save(QJsonArray& missionItems)
void MissionSettingsItem::save(QJsonObject& missionItems)
{
QList<MissionItem*> items;
......
......@@ -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 (QJsonArray& missionItems) final;
void save (QJsonObject& missionItems) final;
double amslEntryAlt (void) const final { return _plannedHomePositionCoordinate.altitude(); }
double amslExitAlt (void) const final { return amslEntryAlt(); }
double minAMSLAltitude (void) const final { return amslEntryAlt(); }
......
......@@ -128,7 +128,7 @@ void RallyPointController::save(QJsonObject& json)
{
json[JsonHelper::jsonVersionKey] = _jsonCurrentVersion;
QJsonArray rgPoints;
QJsonObject rgPoints;
QJsonValue jsonPoint;
for (int i=0; i<_points.count(); i++) {
JsonHelper::saveGeoCoordinate(qobject_cast<RallyPoint*>(_points[i])->coordinate(), true /* writeAltitude */, jsonPoint);
......
......@@ -260,7 +260,7 @@ SimpleMissionItem::~SimpleMissionItem()
{
}
void SimpleMissionItem::save(QJsonArray& missionItems)
void SimpleMissionItem::save(QJsonObject& missionItems)
{
QList<MissionItem*> items;
......
......@@ -127,7 +127,7 @@ public:
void setCoordinate (const QGeoCoordinate& coordinate) override;
void setSequenceNumber (int sequenceNumber) final;
int lastSequenceNumber (void) const final;
void save (QJsonArray& missionItems) final;
void save (QJsonObject& missionItems) final;
signals:
void commandChanged (int command);
......
......@@ -177,7 +177,7 @@ void StructureScanComplexItem::setDirty(bool dirty)
}
}
void StructureScanComplexItem::save(QJsonArray& missionItems)
void StructureScanComplexItem::save(QJsonObject& missionItems)
{
QJsonObject saveObject;
......
......@@ -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 (QJsonArray& missionItems) final;
void save (QJsonObject& missionItems) final;
double amslEntryAlt (void) const final;
double amslExitAlt (void) const final { return amslEntryAlt(); };
double minAMSLAltitude (void) const final;
......
......@@ -110,7 +110,7 @@ void StructureScanComplexItemTest::_testSaveLoad(void)
{
_initItem();
QJsonArray items;
QJsonObject items;
_structureScanItem->save(items);
QString errorString;
......
......@@ -7,16 +7,15 @@
*
****************************************************************************/
#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>
......@@ -24,85 +23,124 @@ 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)
{
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.
// 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())) {
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 (_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);
......@@ -111,56 +149,61 @@ SurveyComplexItem::SurveyComplexItem(PlanMasterController* masterController, boo
setDirty(false);
}
void SurveyComplexItem::save(QJsonArray& planItems)
{
void SurveyComplexItem::save(QJsonObject &planItems) {
QJsonObject saveObject;
_saveWorker(saveObject);
planItems.append(saveObject);
}
void SurveyComplexItem::savePreset(const QString& name)
{
void SurveyComplexItem::savePreset(const QString &name) {
QJsonObject saveObject;
_saveWorker(saveObject);
_savePresetJson(name, saveObject);
}
void SurveyComplexItem::_saveWorker(QJsonObject& saveObject)
{
void SurveyComplexItem::_saveWorker(QJsonObject &saveObject) {
TransectStyleComplexItem::_save(saveObject);
saveObject[JsonHelper::jsonVersionKey] = 5;
saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
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[_jsonFlyAlternateTransectsKey] =
_flyAlternateTransectsFact.rawValue().toBool();
saveObject[_jsonSplitConcavePolygonsKey] =
_splitConcavePolygonsFact.rawValue().toBool();
saveObject[_jsonEntryPointKey] = _entryPoint;
// Polygon shape
_surveyAreaPolygon.saveToJson(saveObject);
}
void SurveyComplexItem::loadPreset(const QString& name)
{
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));
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
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 },
{JsonHelper::jsonVersionKey, QJsonValue::Double, true},
};
if (!JsonHelper::validateKeys(complexObject, versionKeyInfoList, errorString)) {
if (!JsonHelper::validateKeys(complexObject, versionKeyInfoList,
errorString)) {
return false;
}
......@@ -171,7 +214,8 @@ bool SurveyComplexItem::load(const QJsonObject& complexObject, int sequenceNumbe
}
if (version == 4 || version == 5) {
if (!_loadV4V5(complexObject, sequenceNumber, errorString, version, false /* forPresets */)) {
if (!_loadV4V5(complexObject, sequenceNumber, errorString, version,
false /* forPresets */)) {
return false;
}
......@@ -185,9 +229,13 @@ bool SurveyComplexItem::load(const QJsonObject& complexObject, int sequenceNumbe
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 (v3ComplexObject.contains(VisualMissionItem::jsonTypeKey) &&
v3ComplexObject[VisualMissionItem::jsonTypeKey].toString() ==
QStringLiteral("survey")) {
v3ComplexObject[VisualMissionItem::jsonTypeKey] =
VisualMissionItem::jsonTypeComplexItemValue;
v3ComplexObject[ComplexMissionItem::jsonComplexItemTypeKey] =
jsonComplexItemTypeValue;
}
}
if (!_loadV3(complexObject, sequenceNumber, errorString)) {
......@@ -201,18 +249,20 @@ bool SurveyComplexItem::load(const QJsonObject& complexObject, int sequenceNumbe
return true;
}
bool SurveyComplexItem::_loadV4V5(const QJsonObject& complexObject, int sequenceNumber, QString& errorString, int version, bool forPresets)
{
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 },
{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 };
if (version == 5) {
JsonHelper::KeyValidateInfo jSplitPolygon = {_jsonSplitConcavePolygonsKey,
QJsonValue::Bool, true};
keyInfoList.append(jSplitPolygon);
}
......@@ -221,9 +271,15 @@ bool SurveyComplexItem::_loadV4V5(const QJsonObject& complexObject, int sequence
}
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);
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;
}
......@@ -232,22 +288,26 @@ bool SurveyComplexItem::_loadV4V5(const QJsonObject& complexObject, int sequence
if (!forPresets) {
setSequenceNumber(sequenceNumber);
if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */, errorString)) {
if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */,
errorString)) {
_surveyAreaPolygon.clear();
return false;
}
}
if (!TransectStyleComplexItem::_load(complexObject, forPresets, errorString)) {
if (!TransectStyleComplexItem::_load(complexObject, forPresets,
errorString)) {
_ignoreRecalc = false;
return false;
}
_gridAngleFact.setRawValue (complexObject[_jsonGridAngleKey].toDouble());
_flyAlternateTransectsFact.setRawValue (complexObject[_jsonFlyAlternateTransectsKey].toBool(false));
_gridAngleFact.setRawValue(complexObject[_jsonGridAngleKey].toDouble());
_flyAlternateTransectsFact.setRawValue(
complexObject[_jsonFlyAlternateTransectsKey].toBool(false));
if (version == 5) {
_splitConcavePolygonsFact.setRawValue (complexObject[_jsonSplitConcavePolygonsKey].toBool(true));
_splitConcavePolygonsFact.setRawValue(
complexObject[_jsonSplitConcavePolygonsKey].toBool(true));
}
_entryPoint = complexObject[_jsonEntryPointKey].toInt();
......@@ -257,29 +317,37 @@ bool SurveyComplexItem::_loadV4V5(const QJsonObject& complexObject, int sequence
return true;
}
bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
{
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
{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);
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;
}
......@@ -287,22 +355,27 @@ bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNu
setSequenceNumber(sequenceNumber);
_hoverAndCaptureFact.setRawValue (complexObject[_jsonV3HoverAndCaptureKey].toBool(false));
_refly90DegreesFact.setRawValue (complexObject[_jsonV3Refly90DegreesKey].toBool(false));
_cameraTriggerInTurnAroundFact.setRawValue (complexObject[_jsonV3CameraTriggerInTurnaroundKey].toBool(true));
_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));
_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 },
{_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)) {
......@@ -310,8 +383,9 @@ bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNu
return false;
}
_gridAngleFact.setRawValue (gridObject[_jsonV3GridAngleKey].toDouble());
_turnAroundDistanceFact.setRawValue (gridObject[_jsonV3TurnaroundDistKey].toDouble());
_gridAngleFact.setRawValue(gridObject[_jsonV3GridAngleKey].toDouble());
_turnAroundDistanceFact.setRawValue(
gridObject[_jsonV3TurnaroundDistKey].toDouble());
if (gridObject.contains(_jsonEntryPointKey)) {
_entryPoint = gridObject[_jsonEntryPointKey].toInt();
......@@ -319,58 +393,77 @@ bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNu
_entryPoint = EntryLocationTopRight;
}
_cameraCalc.distanceToSurface()->setRawValue (gridObject[_jsonV3GridAltitudeKey].toDouble());
_cameraCalc.adjustedFootprintSide()->setRawValue (gridObject[_jsonV3GridSpacingKey].toDouble());
_cameraCalc.adjustedFootprintFrontal()->setRawValue (complexObject[_jsonV3CameraTriggerDistanceKey].toDouble());
_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");
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"
// Older code had typo on "imageSideOverlap" incorrectly being
// "imageSizeOverlap"
QString incorrectImageSideOverlap = "imageSizeOverlap";
if (cameraObject.contains(incorrectImageSideOverlap)) {
cameraObject[_jsonV3SideOverlapKey] = cameraObject[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 },
{_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)) {
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());
_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
......@@ -379,7 +472,8 @@ bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNu
/// @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)) {
if (!_surveyAreaPolygon.loadFromJson(complexObject, true /* required */,
errorString)) {
_surveyAreaPolygon.clear();
_ignoreRecalc = false;
return false;
......@@ -390,35 +484,39 @@ bool SurveyComplexItem::_loadV3(const QJsonObject& complexObject, int sequenceNu
return true;
}
/// Reverse the order of the transects. First transect becomes last and so forth.
void SurveyComplexItem::_reverseTransectOrder(QList<QList<QGeoCoordinate>>& transects)
{
/// 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--) {
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++) {
/// 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--) {
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)
{
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);
......@@ -427,7 +525,7 @@ void SurveyComplexItem::_optimizeTransectsForShortestDistance(const QGeoCoordina
int shortestIndex = 0;
double shortestDistance = rgTransectDistance[0];
for (int i=1; i<3; i++) {
for (int i = 1; i < 3; i++) {
if (rgTransectDistance[i] < shortestDistance) {
shortestIndex = i;
shortestDistance = rgTransectDistance[i];
......@@ -444,33 +542,34 @@ void SurveyComplexItem::_optimizeTransectsForShortestDistance(const QGeoCoordina
}
}
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)
{
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()
{
/// 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);
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)
{
void SurveyComplexItem::_adjustTransectsToEntryPointLocation(
QList<QList<QGeoCoordinate>> &transects) {
if (transects.count() == 0) {
return;
}
......@@ -478,53 +577,65 @@ void SurveyComplexItem::_adjustTransectsToEntryPointLocation(QList<QList<QGeoCoo
bool reversePoints = false;
bool reverseTransects = false;
if (_entryPoint == EntryLocationBottomLeft || _entryPoint == EntryLocationBottomRight) {
if (_entryPoint == EntryLocationBottomLeft ||
_entryPoint == EntryLocationBottomRight) {
reversePoints = true;
}
if (_entryPoint == EntryLocationTopRight || _entryPoint == EntryLocationBottomRight) {
if (_entryPoint == EntryLocationTopRight ||
_entryPoint == EntryLocationBottomRight) {
reverseTransects = true;
}
if (reversePoints) {
qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation Reverse Points";
qCDebug(SurveyComplexItemLog)
<< "_adjustTransectsToEntryPointLocation Reverse Points";
_reverseInternalTransectPoints(transects);
}
if (reverseTransects) {
qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation Reverse Transects";
qCDebug(SurveyComplexItemLog)
<< "_adjustTransectsToEntryPointLocation Reverse Transects";
_reverseTransectOrder(transects);
}
qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation Modified entry point:entryLocation" << transects.first().first() << _entryPoint;
qCDebug(SurveyComplexItemLog) << "_adjustTransectsToEntryPointLocation "
"Modified entry point:entryLocation"
<< transects.first().first() << _entryPoint;
}
QPointF SurveyComplexItem::_rotatePoint(const QPointF& point, const QPointF& origin, double 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;
}
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());
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++) {
for (int i = 0; i < lineList.count(); i++) {
QPointF intersectPoint;
QLineF intersectLine;
const QLineF& line = lineList[i];
const QLineF &line = lineList[i];
auto isLineBoundedIntersect = [&line, &intersectPoint](const QLineF& linePosition) {
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
};
......@@ -573,18 +684,19 @@ void SurveyComplexItem::_intersectLinesWithRect(const QList<QLineF>& lineList, c
}
}
void SurveyComplexItem::_intersectLinesWithPolygon(const QList<QLineF>& lineList, const QPolygonF& polygon, QList<QLineF>& resultLines)
{
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];
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++) {
for (int j = 0; j < polygon.count() - 1; j++) {
QPointF intersectPoint;
QLineF polygonLine = QLineF(polygon[j], polygon[j+1]);
QLineF polygonLine = QLineF(polygon[j], polygon[j + 1]);
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto intersect = line.intersect(polygonLine, &intersectPoint);
......@@ -598,17 +710,17 @@ void SurveyComplexItem::_intersectLinesWithPolygon(const QList<QLineF>& lineList
}
}
// 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.
// 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++) {
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];
......@@ -623,12 +735,13 @@ void SurveyComplexItem::_intersectLinesWithPolygon(const QList<QLineF>& lineList
}
}
/// 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)
{
/// 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];
for (int i = 0; i < lineList.count(); i++) {
const QLineF &line = lineList[i];
QLineF adjustedLine;
if (i == 0) {
......@@ -646,9 +759,9 @@ void SurveyComplexItem::_adjustLineDirection(const QList<QLineF>& lineList, QLis
}
}
double SurveyComplexItem::_clampGridAngle90(double gridAngle)
{
// Clamp grid angle to -90<->90. This prevents transects from being rotated to a reversed order.
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) {
......@@ -657,8 +770,9 @@ double SurveyComplexItem::_clampGridAngle90(double gridAngle)
return gridAngle;
}
bool SurveyComplexItem::_nextTransectCoord(const QList<QGeoCoordinate>& transectPoints, int pointIndex, QGeoCoordinate& coord)
{
bool SurveyComplexItem::_nextTransectCoord(
const QList<QGeoCoordinate> &transectPoints, int pointIndex,
QGeoCoordinate &coord) {
if (pointIndex > transectPoints.count()) {
qWarning() << "Bad grid generation";
return false;
......@@ -668,18 +782,15 @@ bool SurveyComplexItem::_nextTransectCoord(const QList<QGeoCoordinate>& transect
return true;
}
bool SurveyComplexItem::_hasTurnaround(void) const
{
bool SurveyComplexItem::_hasTurnaround(void) const {
return _turnAroundDistance() > 0;
}
double SurveyComplexItem::_turnaroundDistance(void) const
{
double SurveyComplexItem::_turnaroundDistance(void) const {
return _turnAroundDistanceFact.rawValue().toDouble();
}
void SurveyComplexItem::_rebuildTransectsPhase1(void)
{
void SurveyComplexItem::_rebuildTransectsPhase1(void) {
bool split = splitConcavePolygons()->rawValue().toBool();
if (split) {
_rebuildTransectsPhase1WorkerSplitPolygons(false /* refly */);
......@@ -695,13 +806,13 @@ void SurveyComplexItem::_rebuildTransectsPhase1(void)
}
}
void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool 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 the transects are getting rebuilt then any previously loaded mission
// items are now invalid
if (_loadedMissionItemsParent) {
_loadedMissionItems.clear();
_loadedMissionItemsParent->deleteLater();
......@@ -721,11 +832,18 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
// 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++) {
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();
QGeoCoordinate vertex = _surveyAreaPolygon.pathModel()
.value<QGCQGeoCoordinate *>(i)
->coordinate();
if (i == 0) {
// This avoids a nan calculation that comes out of convertGeoToNed
x = y = 0;
......@@ -733,47 +851,58 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
}
polygonPoints += QPointF(x, y);
qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 vertex:x:y" << vertex << polygonPoints.last().x() << polygonPoints.last().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();
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.
// 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 Clamped grid angle" << gridAngle;
qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing << gridAngle << refly;
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++) {
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();
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.
// 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.
// 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;
......@@ -782,7 +911,10 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
double transectYTop = boundingCenter.y() - halfWidth;
double transectYBottom = boundingCenter.y() + halfWidth;
lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop), boundingCenter, gridAngle), _rotatePoint(QPointF(transectX, transectYBottom), boundingCenter, gridAngle));
lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop),
boundingCenter, gridAngle),
_rotatePoint(QPointF(transectX, transectYBottom),
boundingCenter, gridAngle));
transectX += gridSpacing;
}
......@@ -810,14 +942,15 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
_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.
// 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) {
for (const QLineF &line : resultLines) {
QGeoCoordinate coord;
QList<QGeoCoordinate> transect;
......@@ -832,17 +965,18 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
_adjustTransectsToEntryPointLocation(transects);
if (refly) {
_optimizeTransectsForShortestDistance(_transects.last().last().coord, transects);
_optimizeTransectsForShortestDistance(_transects.last().last().coord,
transects);
}
if (_flyAlternateTransectsFact.rawValue().toBool()) {
QList<QList<QGeoCoordinate>> alternatingTransects;
for (int i=0; i<transects.count(); i++) {
for (int i = 0; i < transects.count(); i++) {
if (!(i & 1)) {
alternatingTransects.append(transects[i]);
}
}
for (int i=transects.count()-1; i>0; i--) {
for (int i = transects.count() - 1; i > 0; i--) {
if (i & 1) {
alternatingTransects.append(transects[i]);
}
......@@ -852,13 +986,14 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
// 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
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--) {
for (int j = transectVertices.count() - 1; j >= 0; j--) {
reversedVertices.append(transectVertices[j]);
}
transectVertices = reversedVertices;
......@@ -869,26 +1004,31 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
}
// Convert to CoordInfo transects and append to _transects
for (const QList<QGeoCoordinate>& transect : transects) {
for (const QList<QGeoCoordinate> &transect : transects) {
QGeoCoordinate coord;
QList<TransectStyleComplexItem::CoordInfo_t> coordInfoTransect;
TransectStyleComplexItem::CoordInfo_t coordInfo;
coordInfo = { transect[0], CoordTypeSurveyEntry };
coordInfo = {transect[0], CoordTypeSurveyEntry};
coordInfoTransect.append(coordInfo);
coordInfo = { transect[1], CoordTypeSurveyExit };
coordInfo = {transect[1], CoordTypeSurveyExit};
coordInfoTransect.append(coordInfo);
// For hover and capture we need points for each camera location within the transect
// 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 };
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);
}
}
......@@ -900,15 +1040,18 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
double turnAroundDistance = _turnAroundDistanceFact.rawValue().toDouble();
double azimuth = transect[0].azimuthTo(transect[1]);
turnaroundCoord = transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord =
transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord.setAltitude(qQNaN());
TransectStyleComplexItem::CoordInfo_t coordInfo = { turnaroundCoord, CoordTypeTurnaround };
TransectStyleComplexItem::CoordInfo_t coordInfo = {turnaroundCoord,
CoordTypeTurnaround};
coordInfoTransect.prepend(coordInfo);
azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
turnaroundCoord = transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord =
transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord.setAltitude(qQNaN());
coordInfo = { turnaroundCoord, CoordTypeTurnaround };
coordInfo = {turnaroundCoord, CoordTypeTurnaround};
coordInfoTransect.append(coordInfo);
}
......@@ -916,14 +1059,13 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSinglePolygon(bool refly)
}
}
void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly)
{
void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly) {
if (_ignoreRecalc) {
return;
}
// If the transects are getting rebuilt then any previously loaded mission items are now invalid
// If the transects are getting rebuilt then any previously loaded mission
// items are now invalid
if (_loadedMissionItemsParent) {
_loadedMissionItems.clear();
_loadedMissionItemsParent->deleteLater();
......@@ -943,11 +1085,18 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly)
// 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++) {
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();
QGeoCoordinate vertex = _surveyAreaPolygon.pathModel()
.value<QGCQGeoCoordinate *>(i)
->coordinate();
if (i == 0) {
// This avoids a nan calculation that comes out of convertGeoToNed
x = y = 0;
......@@ -955,12 +1104,14 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly)
convertGeoToNed(vertex, tangentOrigin, &y, &x, &down);
}
polygonPoints += QPointF(x, y);
qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 vertex:x:y" << vertex << polygonPoints.last().x() << polygonPoints.last().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++) {
for (int i = 0; i < polygonPoints.count(); i++) {
qCDebug(SurveyComplexItemLog) << "Vertex" << polygonPoints[i];
polygon << polygonPoints[i];
}
......@@ -971,38 +1122,38 @@ void SurveyComplexItem::_rebuildTransectsPhase1WorkerSplitPolygons(bool refly)
// iterate over polygons
for (auto p = polygons.begin(); p != polygons.end(); ++p) {
QPointF* vMatch = nullptr;
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) {
for (auto &i : *p) {
for (auto &j : *pLast) {
if (i == j) {
vMatch = &i;
break;
}
if (vMatch) break;
if (vMatch)
break;
}
}
}
// 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;
// qCDebug(SurveyComplexItemLog) << "Transects from polynom p " << p;
_rebuildTransectsFromPolygon(refly, *p, tangentOrigin, vMatch);
}
}
void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<QPolygonF>& decomposedPolygons)
{
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)
return;
if (polygon.size() == 3) {
decomposedPolygons << polygon;
return;
......@@ -1010,33 +1161,40 @@ void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<
QList<QPolygonF> decomposedPolygonsMin{};
for (auto vertex = polygon.begin(); vertex != polygon.end(); ++vertex)
{
for (auto vertex = polygon.begin(); vertex != polygon.end(); ++vertex) {
// is vertex reflex?
bool vertexIsReflex = _VertexIsReflex(polygon, vertex);
if (!vertexIsReflex) continue;
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;
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;
if (!canSee)
continue;
QPolygonF polyLeft;
auto v = vertex;
auto polyLeftContainsReflex = false;
while ( v != vertexOther) {
while (v != vertexOther) {
if (v != vertex && _VertexIsReflex(polygon, v)) {
polyLeftContainsReflex = true;
}
polyLeft << *v;
++v;
if (v == polygon.end()) v = polygon.begin();
if (v == polygon.end())
v = polygon.begin();
}
polyLeft << *vertexOther;
auto polyLeftValid = !(polyLeftContainsReflex && polyLeft.size() == 3);
......@@ -1044,19 +1202,20 @@ void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<
QPolygonF polyRight;
v = vertexOther;
auto polyRightContainsReflex = false;
while ( v != vertex) {
while (v != vertex) {
if (v != vertex && _VertexIsReflex(polygon, v)) {
polyRightContainsReflex = true;
}
polyRight << *v;
++v;
if (v == polygon.end()) v = polygon.begin();
if (v == polygon.end())
v = polygon.begin();
}
polyRight << *vertex;
auto polyRightValid = !(polyRightContainsReflex && polyRight.size() == 3);
if (!polyLeftValid || ! polyRightValid) {
// decompSize = std::numeric_limits<int>::max();
if (!polyLeftValid || !polyRightValid) {
// decompSize = std::numeric_limits<int>::max();
continue;
}
......@@ -1069,9 +1228,8 @@ void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<
// compositon
auto subSize = polyLeftDecomposed.size() + polyRightDecomposed.size();
if ((polyLeftContainsReflex && polyLeftDecomposed.size() == 1)
|| (polyRightContainsReflex && polyRightDecomposed.size() == 1))
{
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();
}
......@@ -1080,7 +1238,6 @@ void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<
decomposedPolygonsMin = polyLeftDecomposed + polyRightDecomposed;
}
}
}
// assemble output
......@@ -1093,27 +1250,40 @@ void SurveyComplexItem::_PolygonDecomposeConvex(const QPolygonF& polygon, QList<
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 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;
// auto diff = *vertexA - *vertexB;
QLineF lineAB{*vertexA, *vertexB};
auto distanceAB = lineAB.length();//sqrtf(diff.x() * diff.x() + diff.y()*diff.y());
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;
// 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;
if (vertexD == vertexA)
continue;
if (vertexD == vertexB)
continue;
QLineF lineCD(*vertexC, *vertexD);
QPointF intersection{};
......@@ -1123,61 +1293,80 @@ bool SurveyComplexItem::_VertexCanSeeOther(const QPolygonF& polygon, const QPoin
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;
// 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;
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;
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())));
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)
{
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();
double gridSpacing =
_cameraCalc.adjustedFootprintSide()->rawValue().toDouble();
gridAngle = _clampGridAngle90(gridAngle);
gridAngle += refly ? 90 : 0;
qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 Clamped grid angle" << gridAngle;
qCDebug(SurveyComplexItemLog)
<< "_rebuildTransectsPhase1 Clamped grid angle" << gridAngle;
qCDebug(SurveyComplexItemLog) << "_rebuildTransectsPhase1 gridSpacing:gridAngle:refly" << gridSpacing << gridAngle << refly;
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();
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.
// 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.
// 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;
......@@ -1186,7 +1375,10 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
double transectYTop = boundingCenter.y() - halfWidth;
double transectYBottom = boundingCenter.y() + halfWidth;
lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop), boundingCenter, gridAngle), _rotatePoint(QPointF(transectX, transectYBottom), boundingCenter, gridAngle));
lineList += QLineF(_rotatePoint(QPointF(transectX, transectYTop),
boundingCenter, gridAngle),
_rotatePoint(QPointF(transectX, transectYBottom),
boundingCenter, gridAngle));
transectX += gridSpacing;
}
......@@ -1214,8 +1406,9 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
_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.
// 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);
......@@ -1225,13 +1418,14 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
if (transitionPoint != nullptr) {
QList<QGeoCoordinate> transect;
QGeoCoordinate coord;
convertNedToGeo(transitionPoint->y(), transitionPoint->x(), 0, tangentOrigin, &coord);
convertNedToGeo(transitionPoint->y(), transitionPoint->x(), 0,
tangentOrigin, &coord);
transect.append(coord);
transect.append(coord); //TODO
transect.append(coord); // TODO
transects.append(transect);
}
for (const QLineF& line: resultLines) {
for (const QLineF &line : resultLines) {
QList<QGeoCoordinate> transect;
QGeoCoordinate coord;
......@@ -1246,17 +1440,18 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
_adjustTransectsToEntryPointLocation(transects);
if (refly) {
_optimizeTransectsForShortestDistance(_transects.last().last().coord, transects);
_optimizeTransectsForShortestDistance(_transects.last().last().coord,
transects);
}
if (_flyAlternateTransectsFact.rawValue().toBool()) {
QList<QList<QGeoCoordinate>> alternatingTransects;
for (int i=0; i<transects.count(); i++) {
for (int i = 0; i < transects.count(); i++) {
if (!(i & 1)) {
alternatingTransects.append(transects[i]);
}
}
for (int i=transects.count()-1; i>0; i--) {
for (int i = transects.count() - 1; i > 0; i--) {
if (i & 1) {
alternatingTransects.append(transects[i]);
}
......@@ -1266,13 +1461,14 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
// 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
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--) {
for (int j = transectVertices.count() - 1; j >= 0; j--) {
reversedVertices.append(transectVertices[j]);
}
transectVertices = reversedVertices;
......@@ -1283,26 +1479,31 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
}
// Convert to CoordInfo transects and append to _transects
for (const QList<QGeoCoordinate>& transect: transects) {
for (const QList<QGeoCoordinate> &transect : transects) {
QGeoCoordinate coord;
QList<TransectStyleComplexItem::CoordInfo_t> coordInfoTransect;
TransectStyleComplexItem::CoordInfo_t coordInfo;
coordInfo = { transect[0], CoordTypeSurveyEntry };
coordInfo = {transect[0], CoordTypeSurveyEntry};
coordInfoTransect.append(coordInfo);
coordInfo = { transect[1], CoordTypeSurveyExit };
coordInfo = {transect[1], CoordTypeSurveyExit};
coordInfoTransect.append(coordInfo);
// For hover and capture we need points for each camera location within the transect
// 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 };
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);
}
}
......@@ -1314,15 +1515,18 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
double turnAroundDistance = _turnAroundDistanceFact.rawValue().toDouble();
double azimuth = transect[0].azimuthTo(transect[1]);
turnaroundCoord = transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord =
transect[0].atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord.setAltitude(qQNaN());
TransectStyleComplexItem::CoordInfo_t coordInfo = { turnaroundCoord, CoordTypeTurnaround };
TransectStyleComplexItem::CoordInfo_t coordInfo = {turnaroundCoord,
CoordTypeTurnaround};
coordInfoTransect.prepend(coordInfo);
azimuth = transect.last().azimuthTo(transect[transect.count() - 2]);
turnaroundCoord = transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord =
transect.last().atDistanceAndAzimuth(-turnAroundDistance, azimuth);
turnaroundCoord.setAltitude(qQNaN());
coordInfo = { turnaroundCoord, CoordTypeTurnaround };
coordInfo = {turnaroundCoord, CoordTypeTurnaround};
coordInfoTransect.append(coordInfo);
}
......@@ -1331,8 +1535,7 @@ void SurveyComplexItem::_rebuildTransectsFromPolygon(bool refly, const QPolygonF
qCDebug(SurveyComplexItemLog) << "_transects.size() " << _transects.size();
}
void SurveyComplexItem::_recalcCameraShots(void)
{
void SurveyComplexItem::_recalcCameraShots(void) {
double triggerDistance = this->triggerDistance();
if (triggerDistance == 0) {
......@@ -1347,38 +1550,44 @@ void SurveyComplexItem::_recalcCameraShots(void)
// 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;
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) {
for (const MissionItem *missionItem : _loadedMissionItems) {
if (missionItem->command() == MAV_CMD_NAV_WAYPOINT) {
if (waitingForTriggerStop) {
distanceEndCoord = QGeoCoordinate(missionItem->param5(), missionItem->param6());
distanceEndCoord = QGeoCoordinate(missionItem->param5(),
missionItem->param6());
} else {
distanceStartCoord = QGeoCoordinate(missionItem->param5(), missionItem->param6());
distanceStartCoord = QGeoCoordinate(missionItem->param5(),
missionItem->param6());
}
} else if (missionItem->command() == MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
} 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);
_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) {
for (const QList<TransectStyleComplexItem::CoordInfo_t> &transect :
_transects) {
QGeoCoordinate firstCameraCoord, lastCameraCoord;
if (_hasTurnaround() && !hoverAndCaptureEnabled()) {
firstCameraCoord = transect[1].coord;
......@@ -1387,7 +1596,8 @@ void SurveyComplexItem::_recalcCameraShots(void)
firstCameraCoord = transect.first().coord;
lastCameraCoord = transect.last().coord;
}
_cameraShots += qCeil(firstCameraCoord.distanceTo(lastCameraCoord) / triggerDistance);
_cameraShots += qCeil(firstCameraCoord.distanceTo(lastCameraCoord) /
triggerDistance);
}
}
}
......@@ -1396,13 +1606,12 @@ void SurveyComplexItem::_recalcCameraShots(void)
emit cameraShotsChanged();
}
SurveyComplexItem::ReadyForSaveState SurveyComplexItem::readyForSaveState(void) const
{
SurveyComplexItem::ReadyForSaveState
SurveyComplexItem::readyForSaveState(void) const {
return TransectStyleComplexItem::readyForSaveState();
}
void SurveyComplexItem::rotateEntryPoint(void)
{
void SurveyComplexItem::rotateEntryPoint(void) {
if (_entryPoint == EntryLocationLast) {
_entryPoint = EntryLocationFirst;
} else {
......@@ -1414,17 +1623,16 @@ void SurveyComplexItem::rotateEntryPoint(void)
setDirty(true);
}
double SurveyComplexItem::timeBetweenShots(void)
{
double SurveyComplexItem::timeBetweenShots(void) {
return _vehicleSpeed == 0 ? 0 : triggerDistance() / _vehicleSpeed;
}
double SurveyComplexItem::additionalTimeDelay (void) const
{
double SurveyComplexItem::additionalTimeDelay(void) const {
double hoverTime = 0;
if (hoverAndCaptureEnabled()) {
for (const QList<TransectStyleComplexItem::CoordInfo_t>& transect: _transects) {
for (const QList<TransectStyleComplexItem::CoordInfo_t> &transect :
_transects) {
hoverTime += _hoverAndCaptureDelaySeconds * transect.count();
}
}
......@@ -1432,8 +1640,7 @@ double SurveyComplexItem::additionalTimeDelay (void) const
return hoverTime;
}
void SurveyComplexItem::_updateWizardMode(void)
{
void SurveyComplexItem::_updateWizardMode(void) {
if (_surveyAreaPolygon.isValid() && !_surveyAreaPolygon.traceMode()) {
setWizardMode(false);
}
......
......@@ -9,53 +9,58 @@
#pragma once
#include "TransectStyleComplexItem.h"
#include "MissionItem.h"
#include "SettingsFact.h"
#include "QGCLoggingCategory.h"
#include "SettingsFact.h"
#include "TransectStyleComplexItem.h"
Q_DECLARE_LOGGING_CATEGORY(SurveyComplexItemLog)
class PlanMasterController;
class SurveyComplexItem : public TransectStyleComplexItem
{
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);
/// @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)
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; }
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 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);
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;
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;
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 {
......@@ -69,24 +74,24 @@ public:
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 *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;
static const char *jsonV3ComplexItemTypeValue;
signals:
void refly90DegreesChanged(bool refly90Degrees);
private slots:
void _updateWizardMode (void);
void _updateWizardMode(void);
// Overrides from TransectStyleComplexItem
void _rebuildTransectsPhase1 (void) final;
void _recalcCameraShots (void) final;
void _rebuildTransectsPhase1(void) final;
void _recalcCameraShots(void) final;
private:
enum CameraTriggerCode {
......@@ -96,19 +101,31 @@ private:
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);
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);
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;
......@@ -117,55 +134,61 @@ private:
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);
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);
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);
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);
bool _VertexCanSeeOther(const QPolygonF &polygon, const QPointF *vertexA,
const QPointF *vertexB);
bool _VertexIsReflex(const QPolygonF &polygon, const QPointF *vertex);
QMap<QString, FactMetaData*> _metaDataMap;
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;
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;
};
......@@ -171,7 +171,7 @@ void TransectStyleComplexItem::_save(QJsonObject& complexObject)
innerObject[_jsonVisualTransectPointsKey] = transectPointsJson;
// Save the interal mission items
QJsonArray missionItemsJsonArray;
QJsonObject 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);
QJsonArray missionItemsJsonArray = innerObject[_jsonItemsKey].toArray();
QJsonObject missionItemsJsonArray = innerObject[_jsonItemsKey].toArray();
for (const QJsonValue missionItemJson: missionItemsJsonArray) {
MissionItem* missionItem = new MissionItem(_loadedMissionItemsParent);
if (!missionItem->load(missionItemJson.toObject(), 0 /* sequenceNumber */, errorString)) {
......
......@@ -86,7 +86,7 @@ public:
double greatestDistanceTo (const QGeoCoordinate &other) const final;
// Overrides from VisualMissionItem
void save (QJsonArray& planItems) override = 0;
void save (QJsonObject& planItems) override = 0;
bool specifiesCoordinate (void) const override = 0;
virtual void appendMissionItems (QList<MissionItem*>& items, QObject* missionItemParent) final;
virtual void applyNewAltitude (double newAltitude) final;
......
......@@ -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 (QJsonArray& missionItems) final { Q_UNUSED(missionItems); }
void save (QJsonObject& missionItems) final { Q_UNUSED(missionItems); }
bool specifiesCoordinate (void) const final { return true; }
double additionalTimeDelay (void) const final { return 0; }
......
......@@ -57,7 +57,7 @@ VTOLLandingComplexItem::VTOLLandingComplexItem(PlanMasterController* masterContr
setDirty(false);
}
void VTOLLandingComplexItem::save(QJsonArray& missionItems)
void VTOLLandingComplexItem::save(QJsonObject& missionItems)
{
QJsonObject saveObject = _save();
......
......@@ -35,7 +35,7 @@ public:
QString mapVisualQML (void) const final { return QStringLiteral("VTOLLandingPatternMapVisual.qml"); }
// Overrides from VisualMissionItem
void save (QJsonArray& missionItems) final;
void save (QJsonObject& missionItems) final;
static const QString name;
......
......@@ -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(QJsonArray& missionItems) = 0;
virtual void save(QJsonObject& missionItems) = 0;
/// @return The QML resource file which contains the control which visualizes the item on the map.
virtual QString mapVisualQML(void) const = 0;
......
......@@ -97,7 +97,7 @@ enum QGCGeoCodeType {
class JasonMonger {
public:
JasonMonger();
QSet<int> json2QGCGeoCodeType(const QJsonArray &types);
QSet<int> json2QGCGeoCodeType(const QJsonObject &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 QJsonArray &types) {
QSet<int> JasonMonger::json2QGCGeoCodeType(const QJsonObject &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;
QJsonArray results = object.value(QStringLiteral("results")).toArray();
QJsonObject 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"))) {
QJsonArray ac = geocode.value(QStringLiteral("address_components")).toArray();
QJsonObject ac = geocode.value(QStringLiteral("address_components")).toArray();
for (int j=0; j<ac.size(); ++j) {
if (!ac[j].isObject())
......
......@@ -223,7 +223,7 @@ void TerrainAirMapQuery::_requestFailed(void)
void TerrainAirMapQuery::_parseCoordinateData(const QJsonValue& coordinateJson)
{
QList<double> heights;
const QJsonArray& dataArray = coordinateJson.toArray();
const QJsonObject& 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();
QJsonArray stepArray = jsonObject["step"].toArray();
QJsonArray profileArray = jsonObject["profile"].toArray();
QJsonObject stepArray = jsonObject["step"].toArray();
QJsonObject 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) {
QJsonArray carpetArray = jsonObject["carpet"].toArray();
QJsonObject carpetArray = jsonObject["carpet"].toArray();
for (int i=0; i<carpetArray.count(); i++) {
QJsonArray rowArray = carpetArray[i].toArray();
QJsonObject rowArray = carpetArray[i].toArray();
carpet.append(QList<double>());
for (int j=0; j<rowArray.count(); j++) {
......
......@@ -229,8 +229,8 @@ QByteArray TerrainTile::serialize(QByteArray input)
QByteArray emptyArray;
return emptyArray;
}
const QJsonArray& swArray = boundsObject[_jsonSouthWestKey].toArray();
const QJsonArray& neArray = boundsObject[_jsonNorthEastKey].toArray();
const QJsonObject& swArray = boundsObject[_jsonSouthWestKey].toArray();
const QJsonObject& 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 QJsonArray& carpetArray = dataObject[_jsonCarpetKey].toArray();
const QJsonObject& 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 QJsonArray& row = carpetArray[i].toArray();
const QJsonObject& row = carpetArray[i].toArray();
if (row.count() < gridSizeLon) {
qCDebug(TerrainTileLog) << "Expected row array of " << gridSizeLon << ", instead got " << row.count();
QByteArray emptyArray;
......
......@@ -68,7 +68,7 @@ void CompInfoParam::setJson(const QString& metadataJsonFileName, const QString&
return;
}
QJsonArray rgParameters = jsonObj[_jsonParametersKey].toArray();
QJsonObject rgParameters = jsonObj[_jsonParametersKey].toArray();
for (QJsonValue parameterValue: rgParameters) {
QMap<QString, QString> emptyDefineMap;
......
......@@ -58,7 +58,7 @@ void CompInfoVersion::setJson(const QString& metadataJsonFileName, const QString
return;
}
QJsonArray rgSupportedTypes = jsonObj[_jsonSupportedCompMetadataTypesKey].toArray();
QJsonObject rgSupportedTypes = jsonObj[_jsonSupportedCompMetadataTypesKey].toArray();
for (QJsonValue typeValue: rgSupportedTypes) {
_supportedTypes.append(static_cast<COMP_METADATA_TYPE>(typeValue.toInt()));
}
......
......@@ -877,7 +877,7 @@ void FirmwareUpgradeController::_px4ReleasesGithubDownloadComplete(QString /*rem
qCWarning(FirmwareUpgradeLog) << "px4 releases json document is not an array" << localFile;
return;
}
QJsonArray releases = doc.array();
QJsonObject 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();
QJsonArray rgFirmware = json[_manifestFirmwareJsonKey].toArray();
QJsonObject 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"));
QJsonArray bootloaderArray = firmwareJson[_manifestBootloaderStrJsonKey].toArray();
QJsonObject bootloaderArray = firmwareJson[_manifestBootloaderStrJsonKey].toArray();
for (int j=0; j<bootloaderArray.count(); j++) {
firmwareInfo.rgBootloaderPortString.append(bootloaderArray[j].toString());
}
QJsonArray usbidArray = firmwareJson[_manifestUSBIDJsonKey].toArray();
QJsonObject usbidArray = firmwareJson[_manifestUSBIDJsonKey].toArray();
for (int j=0; j<usbidArray.count(); j++) {
QStringList vidpid = usbidArray[j].toString().split('/');
QString vid = vidpid[0];
......
......@@ -110,7 +110,7 @@ void QGCSerialPortInfo::_loadJsonData(void)
{ _jsonNameKey, QJsonValue::String, true },
};
QJsonArray rgBoardInfo = json[_jsonBoardInfoKey].toArray();
QJsonObject 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 },
};
QJsonArray rgBoardFallback = json[_jsonBoardDescriptionFallbackKey].toArray();
QJsonObject rgBoardFallback = json[_jsonBoardDescriptionFallbackKey].toArray();
for (int i=0; i<rgBoardFallback.count(); i++) {
const QJsonValue& jsonValue = rgBoardFallback[i];
if (!jsonValue.isObject()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment