Commit 196165c5 authored by Don Gagne's avatar Don Gagne

Structure Scan persistence and mission creation

parent 1ea97d2f
...@@ -21,6 +21,8 @@ const char* CameraCalc::_frontalOverlapName = "FrontalOverlap"; ...@@ -21,6 +21,8 @@ const char* CameraCalc::_frontalOverlapName = "FrontalOverlap";
const char* CameraCalc::_sideOverlapName = "SideOverlap"; const char* CameraCalc::_sideOverlapName = "SideOverlap";
const char* CameraCalc::_adjustedFootprintFrontalName = "AdjustedFootprintFrontal"; const char* CameraCalc::_adjustedFootprintFrontalName = "AdjustedFootprintFrontal";
const char* CameraCalc::_adjustedFootprintSideName = "AdjustedFootprintSide"; const char* CameraCalc::_adjustedFootprintSideName = "AdjustedFootprintSide";
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
const char* CameraCalc::_jsonKnownCameraNameKey = "CameraName";
CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent) CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
: CameraSpec (parent) : CameraSpec (parent)
...@@ -47,8 +49,8 @@ CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent) ...@@ -47,8 +49,8 @@ CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
_imageDensityFact.setMetaData (_metaDataMap[_imageDensityName], true); _imageDensityFact.setMetaData (_metaDataMap[_imageDensityName], true);
_frontalOverlapFact.setMetaData (_metaDataMap[_frontalOverlapName], true); _frontalOverlapFact.setMetaData (_metaDataMap[_frontalOverlapName], true);
_sideOverlapFact.setMetaData (_metaDataMap[_sideOverlapName], true); _sideOverlapFact.setMetaData (_metaDataMap[_sideOverlapName], true);
_adjustedFootprintSideFact.setMetaData (_metaDataMap[_adjustedFootprintSideName], false); _adjustedFootprintSideFact.setMetaData (_metaDataMap[_adjustedFootprintSideName], true);
_adjustedFootprintFrontalFact.setMetaData (_metaDataMap[_adjustedFootprintFrontalName], false); _adjustedFootprintFrontalFact.setMetaData (_metaDataMap[_adjustedFootprintFrontalName], true);
connect(this, &CameraCalc::knownCameraNameChanged, this, &CameraCalc::_knownCameraNameChanged); connect(this, &CameraCalc::knownCameraNameChanged, this, &CameraCalc::_knownCameraNameChanged);
...@@ -71,6 +73,22 @@ void CameraCalc::setDirty(bool dirty) ...@@ -71,6 +73,22 @@ void CameraCalc::setDirty(bool dirty)
} }
} }
void CameraCalc::setCameraSpecType(CameraSpecType cameraSpecType)
{
if (cameraSpecType != _cameraSpecType) {
_cameraSpecType = cameraSpecType;
emit cameraSpecTypeChanged(_cameraSpecType);
}
}
void CameraCalc::setKnownCameraName(QString knownCameraName)
{
if (knownCameraName != _knownCameraName) {
_knownCameraName = knownCameraName;
emit knownCameraNameChanged(_knownCameraName);
}
}
void CameraCalc::_knownCameraNameChanged(QString knownCameraName) void CameraCalc::_knownCameraNameChanged(QString knownCameraName)
{ {
if (_cameraSpecType == CameraSpecKnown) { if (_cameraSpecType == CameraSpecKnown) {
...@@ -150,206 +168,76 @@ void CameraCalc::_recalcTriggerDistance(void) ...@@ -150,206 +168,76 @@ void CameraCalc::_recalcTriggerDistance(void)
void CameraCalc::save(QJsonObject& json) const void CameraCalc::save(QJsonObject& json) const
{ {
Q_UNUSED(json); json[_jsonCameraSpecTypeKey] = (int)_cameraSpecType;
json[_adjustedFootprintSideName] = _adjustedFootprintSideFact.rawValue().toDouble();
#if 0 json[_adjustedFootprintFrontalName] = _adjustedFootprintFrontalFact.rawValue().toDouble();
QJsonObject saveObject; json[_distanceToSurfaceName] = _distanceToSurfaceFact.rawValue().toDouble();
saveObject[JsonHelper::jsonVersionKey] = 3; if (_cameraSpecType != CameraSpecNone) {
saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue; CameraSpec::save(json);
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue; json[_jsonKnownCameraNameKey] = _knownCameraName;
saveObject[_jsonManualGridKey] = _manualGridFact.rawValue().toBool(); json[_valueSetIsDistanceName] = _valueSetIsDistanceFact.rawValue().toBool();
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitudeFact.rawValue().toBool(); json[_imageDensityName] = _imageDensityFact.rawValue().toDouble();
saveObject[_jsonHoverAndCaptureKey] = _hoverAndCaptureFact.rawValue().toBool(); json[_frontalOverlapName] = _frontalOverlapFact.rawValue().toDouble();
saveObject[_jsonRefly90DegreesKey] = _refly90Degrees; json[_sideOverlapName] = _sideOverlapFact.rawValue().toDouble();
saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble();
saveObject[_jsonCameraTriggerInTurnaroundKey] = _cameraTriggerInTurnaroundFact.rawValue().toBool();
QJsonObject gridObject;
gridObject[_jsonGridAltitudeKey] = _gridAltitudeFact.rawValue().toDouble();
gridObject[_jsonGridAltitudeRelativeKey] = _gridAltitudeRelativeFact.rawValue().toBool();
gridObject[_jsonGridAngleKey] = _gridAngleFact.rawValue().toDouble();
gridObject[_jsonGridSpacingKey] = _gridSpacingFact.rawValue().toDouble();
gridObject[_jsonGridEntryLocationKey] = _gridEntryLocationFact.rawValue().toDouble();
gridObject[_jsonTurnaroundDistKey] = _turnaroundDistFact.rawValue().toDouble();
saveObject[_jsonGridObjectKey] = gridObject;
if (!_manualGridFact.rawValue().toBool()) {
QJsonObject cameraObject;
cameraObject[_jsonCameraNameKey] = _cameraFact.rawValue().toString();
cameraObject[_jsonCameraOrientationLandscapeKey] = _cameraOrientationLandscapeFact.rawValue().toBool();
cameraObject[_jsonCameraSensorWidthKey] = _cameraSensorWidthFact.rawValue().toDouble();
cameraObject[_jsonCameraSensorHeightKey] = _cameraSensorHeightFact.rawValue().toDouble();
cameraObject[_jsonCameraResolutionWidthKey] = _cameraResolutionWidthFact.rawValue().toDouble();
cameraObject[_jsonCameraResolutionHeightKey] = _cameraResolutionHeightFact.rawValue().toDouble();
cameraObject[_jsonCameraFocalLengthKey] = _cameraFocalLengthFact.rawValue().toDouble();
cameraObject[_jsonCameraMinTriggerIntervalKey] = _cameraMinTriggerInterval;
cameraObject[_jsonGroundResolutionKey] = _groundResolutionFact.rawValue().toDouble();
cameraObject[_jsonFrontalOverlapKey] = _frontalOverlapFact.rawValue().toInt();
cameraObject[_jsonSideOverlapKey] = _sideOverlapFact.rawValue().toInt();
saveObject[_jsonCameraObjectKey] = cameraObject;
} }
// Polygon shape
_mapPolygon.saveToJson(saveObject);
missionItems.append(saveObject);
#endif
} }
bool CameraCalc::load(const QJsonObject& complexObject, QString& errorString) bool CameraCalc::load(const QJsonObject& json, QString& errorString)
{ {
Q_UNUSED(complexObject); QList<JsonHelper::KeyValidateInfo> keyInfoList1 = {
Q_UNUSED(errorString); { _jsonCameraSpecTypeKey, QJsonValue::Double, true },
#if 0 { _adjustedFootprintSideName, QJsonValue::Double, true },
QJsonObject v2Object = complexObject; { _adjustedFootprintFrontalName, QJsonValue::Double, true },
{ _distanceToSurfaceName, QJsonValue::Double, true },
// We need to pull version first to determine what validation/conversion needs to be performed.
QList<JsonHelper::KeyValidateInfo> versionKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
};
if (!JsonHelper::validateKeys(v2Object, versionKeyInfoList, errorString)) {
return false;
}
int version = v2Object[JsonHelper::jsonVersionKey].toInt();
if (version != 2 && version != 3) {
errorString = tr("%1 does not support this version of survey items").arg(qgcApp()->applicationName());
return false;
}
if (version == 2) {
// Convert to v3
if (v2Object.contains(VisualMissionItem::jsonTypeKey) && v2Object[VisualMissionItem::jsonTypeKey].toString() == QStringLiteral("survey")) {
v2Object[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
v2Object[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
}
}
QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
{ ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true },
{ QGCMapPolygon::jsonPolygonKey, QJsonValue::Array, true },
{ _jsonGridObjectKey, QJsonValue::Object, true },
{ _jsonCameraObjectKey, QJsonValue::Object, false },
{ _jsonCameraTriggerDistanceKey, QJsonValue::Double, true },
{ _jsonManualGridKey, QJsonValue::Bool, true },
{ _jsonFixedValueIsAltitudeKey, QJsonValue::Bool, true },
{ _jsonHoverAndCaptureKey, QJsonValue::Bool, false },
{ _jsonRefly90DegreesKey, QJsonValue::Bool, false },
{ _jsonCameraTriggerInTurnaroundKey, QJsonValue::Bool, false }, // Should really be required, but it was missing from initial code due to bug
}; };
if (!JsonHelper::validateKeys(v2Object, mainKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(json, keyInfoList1, errorString)) {
return false; return false;
} }
QString itemType = v2Object[VisualMissionItem::jsonTypeKey].toString(); int cameraSpecType = json[_jsonCameraSpecTypeKey].toInt();
QString complexType = v2Object[ComplexMissionItem::jsonComplexItemTypeKey].toString(); switch (cameraSpecType) {
if (itemType != VisualMissionItem::jsonTypeComplexItemValue || complexType != jsonComplexItemTypeValue) { case CameraSpecNone:
errorString = tr("%1 does not support loading this complex mission item type: %2:%3").arg(qgcApp()->applicationName()).arg(itemType).arg(complexType); case CameraSpecCustom:
case CameraSpecKnown:
break;
default:
errorString = tr("Unsupported CameraSpecType %d").arg(cameraSpecType);
return false; return false;
} }
_ignoreRecalc = true; _disableRecalc = true;
_mapPolygon.clear();
setSequenceNumber(sequenceNumber);
_manualGridFact.setRawValue (v2Object[_jsonManualGridKey].toBool(true));
_fixedValueIsAltitudeFact.setRawValue (v2Object[_jsonFixedValueIsAltitudeKey].toBool(true));
_gridAltitudeRelativeFact.setRawValue (v2Object[_jsonGridAltitudeRelativeKey].toBool(true));
_hoverAndCaptureFact.setRawValue (v2Object[_jsonHoverAndCaptureKey].toBool(false));
_cameraTriggerInTurnaroundFact.setRawValue (v2Object[_jsonCameraTriggerInTurnaroundKey].toBool(true));
_refly90Degrees = v2Object[_jsonRefly90DegreesKey].toBool(false);
QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
{ _jsonGridAltitudeKey, QJsonValue::Double, true },
{ _jsonGridAltitudeRelativeKey, QJsonValue::Bool, true },
{ _jsonGridAngleKey, QJsonValue::Double, true },
{ _jsonGridSpacingKey, QJsonValue::Double, true },
{ _jsonGridEntryLocationKey, QJsonValue::Double, false },
{ _jsonTurnaroundDistKey, QJsonValue::Double, true },
};
QJsonObject gridObject = v2Object[_jsonGridObjectKey].toObject();
if (!JsonHelper::validateKeys(gridObject, gridKeyInfoList, errorString)) {
return false;
}
_gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (gridObject[_jsonGridSpacingKey].toDouble());
_turnaroundDistFact.setRawValue (gridObject[_jsonTurnaroundDistKey].toDouble());
_cameraTriggerDistanceFact.setRawValue (v2Object[_jsonCameraTriggerDistanceKey].toDouble());
if (gridObject.contains(_jsonGridEntryLocationKey)) {
_gridEntryLocationFact.setRawValue(gridObject[_jsonGridEntryLocationKey].toDouble());
} else {
_gridEntryLocationFact.setRawValue(_gridEntryLocationFact.rawDefaultValue());
}
if (!_manualGridFact.rawValue().toBool()) { setCameraSpecType((CameraSpecType)cameraSpecType);
if (!v2Object.contains(_jsonCameraObjectKey)) { _adjustedFootprintSideFact.setRawValue (json[_adjustedFootprintSideName].toDouble());
errorString = tr("%1 but %2 object is missing").arg("manualGrid = false").arg("camera"); _adjustedFootprintFrontalFact.setRawValue (json[_adjustedFootprintFrontalName].toDouble());
_distanceToSurfaceFact.setRawValue (json[_distanceToSurfaceName].toDouble());
if (_cameraSpecType != CameraSpecNone) {
QList<JsonHelper::KeyValidateInfo> keyInfoList2 = {
{ _jsonKnownCameraNameKey, QJsonValue::String, true },
{ _valueSetIsDistanceName, QJsonValue::Bool, true },
{ _imageDensityName, QJsonValue::Double, true },
{ _frontalOverlapName, QJsonValue::Double, true },
{ _sideOverlapName, QJsonValue::Double, true },
};
if (!JsonHelper::validateKeys(json, keyInfoList2, errorString)) {
return false; return false;
_disableRecalc = false;
} }
QJsonObject cameraObject = v2Object[_jsonCameraObjectKey].toObject(); setKnownCameraName(json[_jsonKnownCameraNameKey].toString());
_valueSetIsDistanceFact.setRawValue (json[_valueSetIsDistanceName].toBool());
_imageDensityFact.setRawValue (json[_imageDensityName].toDouble());
_frontalOverlapFact.setRawValue (json[_frontalOverlapName].toDouble());
_sideOverlapFact.setRawValue (json[_sideOverlapName].toDouble());
// Older code had typo on "imageSideOverlap" incorrectly being "imageSizeOverlap" if (!CameraSpec::load(json, errorString)) {
QString incorrectImageSideOverlap = "imageSizeOverlap";
if (cameraObject.contains(incorrectImageSideOverlap)) {
cameraObject[_jsonSideOverlapKey] = cameraObject[incorrectImageSideOverlap];
cameraObject.remove(incorrectImageSideOverlap);
}
QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
{ _jsonGroundResolutionKey, QJsonValue::Double, true },
{ _jsonFrontalOverlapKey, QJsonValue::Double, true },
{ _jsonSideOverlapKey, QJsonValue::Double, true },
{ _jsonCameraSensorWidthKey, QJsonValue::Double, true },
{ _jsonCameraSensorHeightKey, QJsonValue::Double, true },
{ _jsonCameraResolutionWidthKey, QJsonValue::Double, true },
{ _jsonCameraResolutionHeightKey, QJsonValue::Double, true },
{ _jsonCameraFocalLengthKey, QJsonValue::Double, true },
{ _jsonCameraNameKey, QJsonValue::String, true },
{ _jsonCameraOrientationLandscapeKey, QJsonValue::Bool, true },
{ _jsonCameraMinTriggerIntervalKey, QJsonValue::Double, false },
};
if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList, errorString)) {
return false; return false;
} }
_cameraFact.setRawValue(cameraObject[_jsonCameraNameKey].toString());
_cameraOrientationLandscapeFact.setRawValue(cameraObject[_jsonCameraOrientationLandscapeKey].toBool(true));
_groundResolutionFact.setRawValue (cameraObject[_jsonGroundResolutionKey].toDouble());
_frontalOverlapFact.setRawValue (cameraObject[_jsonFrontalOverlapKey].toInt());
_sideOverlapFact.setRawValue (cameraObject[_jsonSideOverlapKey].toInt());
_cameraSensorWidthFact.setRawValue (cameraObject[_jsonCameraSensorWidthKey].toDouble());
_cameraSensorHeightFact.setRawValue (cameraObject[_jsonCameraSensorHeightKey].toDouble());
_cameraResolutionWidthFact.setRawValue (cameraObject[_jsonCameraResolutionWidthKey].toDouble());
_cameraResolutionHeightFact.setRawValue (cameraObject[_jsonCameraResolutionHeightKey].toDouble());
_cameraFocalLengthFact.setRawValue (cameraObject[_jsonCameraFocalLengthKey].toDouble());
_cameraMinTriggerInterval = cameraObject[_jsonCameraMinTriggerIntervalKey].toDouble(0);
} }
// Polygon shape _disableRecalc = false;
/// Load a polygon from json
/// @param json Json object to load from
/// @param required true: no polygon in object will generate error
/// @param errorString Error string if return is false
/// @return true: success, false: failure (errorString set)
if (!_mapPolygon.loadFromJson(v2Object, true /* required */, errorString)) {
_mapPolygon.clear();
return false;
}
_ignoreRecalc = false;
_generateGrid();
return true; return true;
#endif
return false;
} }
...@@ -22,8 +22,8 @@ public: ...@@ -22,8 +22,8 @@ public:
Q_ENUMS(CameraSpecType) Q_ENUMS(CameraSpecType)
Q_PROPERTY(CameraSpecType cameraSpecType MEMBER _cameraSpecType NOTIFY cameraSpecTypeChanged) Q_PROPERTY(CameraSpecType cameraSpecType READ cameraSpecType WRITE setCameraSpecType NOTIFY cameraSpecTypeChanged)
Q_PROPERTY(QString knownCameraName MEMBER _knownCameraName NOTIFY knownCameraNameChanged) Q_PROPERTY(QString knownCameraName READ knownCameraName WRITE setKnownCameraName NOTIFY knownCameraNameChanged)
Q_PROPERTY(Fact* valueSetIsDistance READ valueSetIsDistance CONSTANT) ///< true: distance specified, resolution calculated Q_PROPERTY(Fact* valueSetIsDistance READ valueSetIsDistance CONSTANT) ///< true: distance specified, resolution calculated
Q_PROPERTY(Fact* distanceToSurface READ distanceToSurface CONSTANT) ///< Distance to surface for image foot print calculation Q_PROPERTY(Fact* distanceToSurface READ distanceToSurface CONSTANT) ///< Distance to surface for image foot print calculation
Q_PROPERTY(Fact* imageDensity READ imageDensity CONSTANT) ///< Image density on surface (cm/px) Q_PROPERTY(Fact* imageDensity READ imageDensity CONSTANT) ///< Image density on surface (cm/px)
...@@ -42,6 +42,11 @@ public: ...@@ -42,6 +42,11 @@ public:
CameraSpecKnown CameraSpecKnown
}; };
CameraSpecType cameraSpecType(void) const { return _cameraSpecType; }
QString knownCameraName(void) const { return _knownCameraName; }
void setCameraSpecType(CameraSpecType cameraSpecType);
void setKnownCameraName(QString knownCameraName);
Fact* valueSetIsDistance (void) { return &_valueSetIsDistanceFact; } Fact* valueSetIsDistance (void) { return &_valueSetIsDistanceFact; }
Fact* distanceToSurface (void) { return &_distanceToSurfaceFact; } Fact* distanceToSurface (void) { return &_distanceToSurfaceFact; }
Fact* imageDensity (void) { return &_imageDensityFact; } Fact* imageDensity (void) { return &_imageDensityFact; }
...@@ -99,4 +104,6 @@ private: ...@@ -99,4 +104,6 @@ private:
static const char* _sideOverlapName; static const char* _sideOverlapName;
static const char* _adjustedFootprintSideName; static const char* _adjustedFootprintSideName;
static const char* _adjustedFootprintFrontalName; static const char* _adjustedFootprintFrontalName;
static const char* _jsonCameraSpecTypeKey;
static const char* _jsonKnownCameraNameKey;
}; };
...@@ -12,16 +12,6 @@ ...@@ -12,16 +12,6 @@
#include <QQmlEngine> #include <QQmlEngine>
const char* CameraSpec::_jsonSensorWidthKey = "sensorWidth";
const char* CameraSpec::_jsonSensorHeightKey = "sensorHeight";
const char* CameraSpec::_jsonImageWidthKey = "imageWidth";
const char* CameraSpec::_jsonImageHeightKey = "imageHeight";
const char* CameraSpec::_jsonFocalLengthKey = "focalLength";
const char* CameraSpec::_jsonMinTriggerIntervalKey = "minTriggerInterval";
const char* CameraSpec::_jsonNameKey = "name";
const char* CameraSpec::_jsonLandscapeKey = "orientationLandscape";
const char* CameraSpec::_nameName = "Camera";
const char* CameraSpec::_sensorWidthName = "SensorWidth"; const char* CameraSpec::_sensorWidthName = "SensorWidth";
const char* CameraSpec::_sensorHeightName = "SensorHeight"; const char* CameraSpec::_sensorHeightName = "SensorHeight";
const char* CameraSpec::_imageWidthName = "ImageWidth"; const char* CameraSpec::_imageWidthName = "ImageWidth";
...@@ -35,7 +25,6 @@ CameraSpec::CameraSpec(QObject* parent) ...@@ -35,7 +25,6 @@ CameraSpec::CameraSpec(QObject* parent)
: QObject (parent) : QObject (parent)
, _dirty (false) , _dirty (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this)) , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this))
, _nameFact (0, _nameName, FactMetaData::valueTypeString)
, _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble) , _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble)
, _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble) , _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble)
, _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32) , _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32)
...@@ -48,47 +37,10 @@ CameraSpec::CameraSpec(QObject* parent) ...@@ -48,47 +37,10 @@ CameraSpec::CameraSpec(QObject* parent)
_init(true); _init(true);
} }
CameraSpec::CameraSpec(const QString& name,
double sensorWidth,
double sensorHeight,
double imageWidth,
double imageHeight,
double focalLength,
bool landscape,
bool fixedOrientation,
double minTriggerInterval,
QObject* parent)
: QObject (parent)
, _dirty (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this))
, _nameFact (0, _nameName, FactMetaData::valueTypeString)
, _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble)
, _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble)
, _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32)
, _imageHeightFact (0, _imageHeightName, FactMetaData::valueTypeUint32)
, _focalLengthFact (0, _focalLengthName, FactMetaData::valueTypeDouble)
, _landscapeFact (0, _landscapeName, FactMetaData::valueTypeBool)
, _fixedOrientationFact (0, _fixedOrientationName, FactMetaData::valueTypeBool)
, _minTriggerIntervalFact (0, _minTriggerIntervalName, FactMetaData::valueTypeDouble)
{
_init(false);
_nameFact.setRawValue (name);
_sensorWidthFact.setRawValue (sensorWidth);
_sensorHeightFact.setRawValue (sensorHeight);
_imageWidthFact.setRawValue (imageWidth);
_imageHeightFact.setRawValue (imageHeight);
_focalLengthFact.setRawValue (focalLength);
_landscapeFact.setRawValue (landscape);
_fixedOrientationFact.setRawValue (fixedOrientation);
_minTriggerIntervalFact.setRawValue (minTriggerInterval);
}
CameraSpec::CameraSpec(const CameraSpec& other, QObject* parent) CameraSpec::CameraSpec(const CameraSpec& other, QObject* parent)
: QObject (parent) : QObject (parent)
, _dirty (false) , _dirty (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this)) , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSpec.FactMetaData.json"), this))
, _nameFact (0, _nameName, FactMetaData::valueTypeString)
, _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble) , _sensorWidthFact (0, _sensorWidthName, FactMetaData::valueTypeDouble)
, _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble) , _sensorHeightFact (0, _sensorHeightName, FactMetaData::valueTypeDouble)
, _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32) , _imageWidthFact (0, _imageWidthName, FactMetaData::valueTypeUint32)
...@@ -105,7 +57,6 @@ CameraSpec::CameraSpec(const CameraSpec& other, QObject* parent) ...@@ -105,7 +57,6 @@ CameraSpec::CameraSpec(const CameraSpec& other, QObject* parent)
const CameraSpec& CameraSpec::operator=(const CameraSpec& other) const CameraSpec& CameraSpec::operator=(const CameraSpec& other)
{ {
_nameFact.setRawValue (other._nameFact.rawValue());
_sensorWidthFact.setRawValue (other._sensorWidthFact.rawValue()); _sensorWidthFact.setRawValue (other._sensorWidthFact.rawValue());
_sensorHeightFact.setRawValue (other._sensorHeightFact.rawValue()); _sensorHeightFact.setRawValue (other._sensorHeightFact.rawValue());
_imageWidthFact.setRawValue (other._imageWidthFact.rawValue()); _imageWidthFact.setRawValue (other._imageWidthFact.rawValue());
...@@ -122,7 +73,6 @@ void CameraSpec::_init(bool setDefaults) ...@@ -122,7 +73,6 @@ void CameraSpec::_init(bool setDefaults)
{ {
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
_nameFact.setMetaData (_metaDataMap[_nameName], setDefaults /* setDefaultFromMetaData */);
_sensorWidthFact.setMetaData (_metaDataMap[_sensorWidthName], setDefaults); _sensorWidthFact.setMetaData (_metaDataMap[_sensorWidthName], setDefaults);
_sensorHeightFact.setMetaData (_metaDataMap[_sensorHeightName], setDefaults); _sensorHeightFact.setMetaData (_metaDataMap[_sensorHeightName], setDefaults);
_imageWidthFact.setMetaData (_metaDataMap[_imageWidthName], setDefaults); _imageWidthFact.setMetaData (_metaDataMap[_imageWidthName], setDefaults);
...@@ -143,255 +93,40 @@ void CameraSpec::setDirty(bool dirty) ...@@ -143,255 +93,40 @@ void CameraSpec::setDirty(bool dirty)
void CameraSpec::save(QJsonObject& json) const void CameraSpec::save(QJsonObject& json) const
{ {
Q_UNUSED(json); json[_sensorWidthName] = _sensorWidthFact.rawValue().toDouble();
#if 0 json[_sensorHeightName] = _sensorHeightFact.rawValue().toDouble();
QJsonObject saveObject; json[_imageWidthName] = _imageWidthFact.rawValue().toDouble();
json[_imageHeightName] = _imageHeightFact.rawValue().toDouble();
saveObject[JsonHelper::jsonVersionKey] = 3; json[_focalLengthName] = _focalLengthFact.rawValue().toDouble();
saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue; json[_landscapeName] = _landscapeFact.rawValue().toBool();
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue; json[_fixedOrientationName] = _fixedOrientationFact.rawValue().toBool();
saveObject[_jsonManualGridKey] = _manualGridFact.rawValue().toBool(); json[_minTriggerIntervalName] = _minTriggerIntervalFact.rawValue().toDouble();
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitudeFact.rawValue().toBool();
saveObject[_jsonHoverAndCaptureKey] = _hoverAndCaptureFact.rawValue().toBool();
saveObject[_jsonRefly90DegreesKey] = _refly90Degrees;
saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble();
saveObject[_jsonCameraTriggerInTurnaroundKey] = _cameraTriggerInTurnaroundFact.rawValue().toBool();
QJsonObject gridObject;
gridObject[_jsonGridAltitudeKey] = _gridAltitudeFact.rawValue().toDouble();
gridObject[_jsonGridAltitudeRelativeKey] = _gridAltitudeRelativeFact.rawValue().toBool();
gridObject[_jsonGridAngleKey] = _gridAngleFact.rawValue().toDouble();
gridObject[_jsonGridSpacingKey] = _gridSpacingFact.rawValue().toDouble();
gridObject[_jsonGridEntryLocationKey] = _gridEntryLocationFact.rawValue().toDouble();
gridObject[_jsonTurnaroundDistKey] = _turnaroundDistFact.rawValue().toDouble();
saveObject[_jsonGridObjectKey] = gridObject;
if (!_manualGridFact.rawValue().toBool()) {
QJsonObject cameraObject;
cameraObject[_jsonCameraNameKey] = _cameraFact.rawValue().toString();
cameraObject[_jsonCameraOrientationLandscapeKey] = _cameraOrientationLandscapeFact.rawValue().toBool();
cameraObject[_jsonCameraSensorWidthKey] = _cameraSensorWidthFact.rawValue().toDouble();
cameraObject[_jsonCameraSensorHeightKey] = _cameraSensorHeightFact.rawValue().toDouble();
cameraObject[_jsonCameraResolutionWidthKey] = _cameraResolutionWidthFact.rawValue().toDouble();
cameraObject[_jsonCameraResolutionHeightKey] = _cameraResolutionHeightFact.rawValue().toDouble();
cameraObject[_jsonCameraFocalLengthKey] = _cameraFocalLengthFact.rawValue().toDouble();
cameraObject[_jsonCameraMinTriggerIntervalKey] = _cameraMinTriggerInterval;
cameraObject[_jsonGroundResolutionKey] = _groundResolutionFact.rawValue().toDouble();
cameraObject[_jsonFrontalOverlapKey] = _frontalOverlapFact.rawValue().toInt();
cameraObject[_jsonSideOverlapKey] = _sideOverlapFact.rawValue().toInt();
saveObject[_jsonCameraObjectKey] = cameraObject;
}
// Polygon shape
_mapPolygon.saveToJson(saveObject);
missionItems.append(saveObject);
#endif
} }
bool CameraSpec::load(const QJsonObject& complexObject, QString& errorString) bool CameraSpec::load(const QJsonObject& json, QString& errorString)
{ {
Q_UNUSED(complexObject); QList<JsonHelper::KeyValidateInfo> keyInfoList = {
Q_UNUSED(errorString); { _sensorWidthName, QJsonValue::Double, true },
#if 0 { _sensorHeightName, QJsonValue::Double, true },
QJsonObject v2Object = complexObject; { _imageWidthName, QJsonValue::Double, true },
{ _imageHeightName, QJsonValue::Double, true },
// We need to pull version first to determine what validation/conversion needs to be performed. { _focalLengthName, QJsonValue::Double, true },
QList<JsonHelper::KeyValidateInfo> versionKeyInfoList = { { _landscapeName, QJsonValue::Bool, true },
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true }, { _fixedOrientationName, QJsonValue::Bool, true },
}; { _minTriggerIntervalName, QJsonValue::Double, true },
if (!JsonHelper::validateKeys(v2Object, versionKeyInfoList, errorString)) {
return false;
}
int version = v2Object[JsonHelper::jsonVersionKey].toInt();
if (version != 2 && version != 3) {
errorString = tr("%1 does not support this version of survey items").arg(qgcApp()->applicationName());
return false;
}
if (version == 2) {
// Convert to v3
if (v2Object.contains(VisualMissionItem::jsonTypeKey) && v2Object[VisualMissionItem::jsonTypeKey].toString() == QStringLiteral("survey")) {
v2Object[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
v2Object[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
}
}
QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
{ ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true },
{ QGCMapPolygon::jsonPolygonKey, QJsonValue::Array, true },
{ _jsonGridObjectKey, QJsonValue::Object, true },
{ _jsonCameraObjectKey, QJsonValue::Object, false },
{ _jsonCameraTriggerDistanceKey, QJsonValue::Double, true },
{ _jsonManualGridKey, QJsonValue::Bool, true },
{ _jsonFixedValueIsAltitudeKey, QJsonValue::Bool, true },
{ _jsonHoverAndCaptureKey, QJsonValue::Bool, false },
{ _jsonRefly90DegreesKey, QJsonValue::Bool, false },
{ _jsonCameraTriggerInTurnaroundKey, QJsonValue::Bool, false }, // Should really be required, but it was missing from initial code due to bug
}; };
if (!JsonHelper::validateKeys(v2Object, mainKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(json, keyInfoList, errorString)) {
return false; return false;
} }
QString itemType = v2Object[VisualMissionItem::jsonTypeKey].toString(); _sensorWidthFact.setRawValue (json[_sensorWidthName].toDouble());
QString complexType = v2Object[ComplexMissionItem::jsonComplexItemTypeKey].toString(); _sensorHeightFact.setRawValue (json[_sensorHeightName].toDouble());
if (itemType != VisualMissionItem::jsonTypeComplexItemValue || complexType != jsonComplexItemTypeValue) { _imageWidthFact.setRawValue (json[_imageWidthName].toDouble());
errorString = tr("%1 does not support loading this complex mission item type: %2:%3").arg(qgcApp()->applicationName()).arg(itemType).arg(complexType); _imageHeightFact.setRawValue (json[_imageHeightName].toDouble());
return false; _focalLengthFact.setRawValue (json[_focalLengthName].toDouble());
} _landscapeFact.setRawValue (json[_landscapeName].toBool());
_fixedOrientationFact.setRawValue (json[_fixedOrientationName].toBool());
_ignoreRecalc = true; _minTriggerIntervalFact.setRawValue (json[_minTriggerIntervalName].toDouble());
_mapPolygon.clear();
setSequenceNumber(sequenceNumber);
_manualGridFact.setRawValue (v2Object[_jsonManualGridKey].toBool(true));
_fixedValueIsAltitudeFact.setRawValue (v2Object[_jsonFixedValueIsAltitudeKey].toBool(true));
_gridAltitudeRelativeFact.setRawValue (v2Object[_jsonGridAltitudeRelativeKey].toBool(true));
_hoverAndCaptureFact.setRawValue (v2Object[_jsonHoverAndCaptureKey].toBool(false));
_cameraTriggerInTurnaroundFact.setRawValue (v2Object[_jsonCameraTriggerInTurnaroundKey].toBool(true));
_refly90Degrees = v2Object[_jsonRefly90DegreesKey].toBool(false);
QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
{ _jsonGridAltitudeKey, QJsonValue::Double, true },
{ _jsonGridAltitudeRelativeKey, QJsonValue::Bool, true },
{ _jsonGridAngleKey, QJsonValue::Double, true },
{ _jsonGridSpacingKey, QJsonValue::Double, true },
{ _jsonGridEntryLocationKey, QJsonValue::Double, false },
{ _jsonTurnaroundDistKey, QJsonValue::Double, true },
};
QJsonObject gridObject = v2Object[_jsonGridObjectKey].toObject();
if (!JsonHelper::validateKeys(gridObject, gridKeyInfoList, errorString)) {
return false;
}
_gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (gridObject[_jsonGridSpacingKey].toDouble());
_turnaroundDistFact.setRawValue (gridObject[_jsonTurnaroundDistKey].toDouble());
_cameraTriggerDistanceFact.setRawValue (v2Object[_jsonCameraTriggerDistanceKey].toDouble());
if (gridObject.contains(_jsonGridEntryLocationKey)) {
_gridEntryLocationFact.setRawValue(gridObject[_jsonGridEntryLocationKey].toDouble());
} else {
_gridEntryLocationFact.setRawValue(_gridEntryLocationFact.rawDefaultValue());
}
if (!_manualGridFact.rawValue().toBool()) {
if (!v2Object.contains(_jsonCameraObjectKey)) {
errorString = tr("%1 but %2 object is missing").arg("manualGrid = false").arg("camera");
return false;
}
QJsonObject cameraObject = v2Object[_jsonCameraObjectKey].toObject();
// Older code had typo on "imageSideOverlap" incorrectly being "imageSizeOverlap"
QString incorrectImageSideOverlap = "imageSizeOverlap";
if (cameraObject.contains(incorrectImageSideOverlap)) {
cameraObject[_jsonSideOverlapKey] = cameraObject[incorrectImageSideOverlap];
cameraObject.remove(incorrectImageSideOverlap);
}
QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
{ _jsonGroundResolutionKey, QJsonValue::Double, true },
{ _jsonFrontalOverlapKey, QJsonValue::Double, true },
{ _jsonSideOverlapKey, QJsonValue::Double, true },
{ _jsonCameraSensorWidthKey, QJsonValue::Double, true },
{ _jsonCameraSensorHeightKey, QJsonValue::Double, true },
{ _jsonCameraResolutionWidthKey, QJsonValue::Double, true },
{ _jsonCameraResolutionHeightKey, QJsonValue::Double, true },
{ _jsonCameraFocalLengthKey, QJsonValue::Double, true },
{ _jsonCameraNameKey, QJsonValue::String, true },
{ _jsonCameraOrientationLandscapeKey, QJsonValue::Bool, true },
{ _jsonCameraMinTriggerIntervalKey, QJsonValue::Double, false },
};
if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList, errorString)) {
return false;
}
_cameraFact.setRawValue(cameraObject[_jsonCameraNameKey].toString());
_cameraOrientationLandscapeFact.setRawValue(cameraObject[_jsonCameraOrientationLandscapeKey].toBool(true));
_groundResolutionFact.setRawValue (cameraObject[_jsonGroundResolutionKey].toDouble());
_frontalOverlapFact.setRawValue (cameraObject[_jsonFrontalOverlapKey].toInt());
_sideOverlapFact.setRawValue (cameraObject[_jsonSideOverlapKey].toInt());
_cameraSensorWidthFact.setRawValue (cameraObject[_jsonCameraSensorWidthKey].toDouble());
_cameraSensorHeightFact.setRawValue (cameraObject[_jsonCameraSensorHeightKey].toDouble());
_cameraResolutionWidthFact.setRawValue (cameraObject[_jsonCameraResolutionWidthKey].toDouble());
_cameraResolutionHeightFact.setRawValue (cameraObject[_jsonCameraResolutionHeightKey].toDouble());
_cameraFocalLengthFact.setRawValue (cameraObject[_jsonCameraFocalLengthKey].toDouble());
_cameraMinTriggerInterval = cameraObject[_jsonCameraMinTriggerIntervalKey].toDouble(0);
}
// Polygon shape
/// Load a polygon from json
/// @param json Json object to load from
/// @param required true: no polygon in object will generate error
/// @param errorString Error string if return is false
/// @return true: success, false: failure (errorString set)
if (!_mapPolygon.loadFromJson(v2Object, true /* required */, errorString)) {
_mapPolygon.clear();
return false;
}
_ignoreRecalc = false;
_generateGrid();
return true; return true;
#endif
return false;
}
#if 0
void CameraSpec::recalcImageOnGround(bool valueIsAltitude, double value)
{
var focalLength = missionItem.cameraFocalLength.rawValue
var sensorWidth = missionItem.cameraSensorWidth.rawValue
var sensorHeight = missionItem.cameraSensorHeight.rawValue
var imageWidth = missionItem.cameraResolutionWidth.rawValue
var imageHeight = missionItem.cameraResolutionHeight.rawValue
var altitude = missionItem.gridAltitude.rawValue
var groundResolution= missionItem.groundResolution.rawValue
var frontalOverlap = missionItem.frontalOverlap.rawValue
var sideOverlap = missionItem.sideOverlap.rawValue
if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || groundResolution <= 0) {
return
}
var imageSizeSideGround //size in side (non flying) direction of the image on the ground
var imageSizeFrontGround //size in front (flying) direction of the image on the ground
var gridSpacing
var cameraTriggerDistance
if (missionItem.fixedValueIsAltitude.value) {
groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
} else {
altitude = (imageWidth * groundResolution * focalLength) / (sensorWidth * 100)
}
if (missionItem.cameraOrientationLandscape.value) {
imageSizeSideGround = (imageWidth * groundResolution) / 100
imageSizeFrontGround = (imageHeight * groundResolution) / 100
} else {
imageSizeSideGround = (imageHeight * groundResolution) / 100
imageSizeFrontGround = (imageWidth * groundResolution) / 100
}
gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 )
cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 )
if (missionItem.fixedValueIsAltitude.value) {
missionItem.groundResolution.rawValue = groundResolution
} else {
missionItem.gridAltitude.rawValue = altitude
}
missionItem.gridSpacing.rawValue = gridSpacing
missionItem.cameraTriggerDistance.rawValue = cameraTriggerDistance
} }
#endif
...@@ -17,22 +17,11 @@ class CameraSpec : public QObject ...@@ -17,22 +17,11 @@ class CameraSpec : public QObject
public: public:
CameraSpec(QObject* parent = NULL); CameraSpec(QObject* parent = NULL);
CameraSpec(const QString& name,
double sensorWidth,
double sensorHeight,
double imageWidth,
double imageHeight,
double focalLength,
bool landscape,
bool fixedOrientation,
double minTriggerInterval,
QObject* parent = NULL);
CameraSpec(const CameraSpec& other, QObject* parent); CameraSpec(const CameraSpec& other, QObject* parent);
const CameraSpec& operator=(const CameraSpec& other); const CameraSpec& operator=(const CameraSpec& other);
// These properties are persisted to Json // These properties are persisted to Json
Q_PROPERTY(Fact* name READ name CONSTANT) ///< Camera name
Q_PROPERTY(Fact* sensorWidth READ sensorWidth CONSTANT) ///< Sensor size in millimeters Q_PROPERTY(Fact* sensorWidth READ sensorWidth CONSTANT) ///< Sensor size in millimeters
Q_PROPERTY(Fact* sensorHeight READ sensorHeight CONSTANT) ///< Sensor size in millimeters Q_PROPERTY(Fact* sensorHeight READ sensorHeight CONSTANT) ///< Sensor size in millimeters
Q_PROPERTY(Fact* imageWidth READ imageWidth CONSTANT) ///< Image size in pixels Q_PROPERTY(Fact* imageWidth READ imageWidth CONSTANT) ///< Image size in pixels
...@@ -42,7 +31,6 @@ public: ...@@ -42,7 +31,6 @@ public:
Q_PROPERTY(Fact* fixedOrientation READ fixedOrientation CONSTANT) ///< true: camera is in fixed orientation Q_PROPERTY(Fact* fixedOrientation READ fixedOrientation CONSTANT) ///< true: camera is in fixed orientation
Q_PROPERTY(Fact* minTriggerInterval READ minTriggerInterval CONSTANT) ///< Minimum time in seconds between each photo taken, 0 for not specified Q_PROPERTY(Fact* minTriggerInterval READ minTriggerInterval CONSTANT) ///< Minimum time in seconds between each photo taken, 0 for not specified
Fact* name (void) { return &_nameFact; }
Fact* sensorWidth (void) { return &_sensorWidthFact; } Fact* sensorWidth (void) { return &_sensorWidthFact; }
Fact* sensorHeight (void) { return &_sensorHeightFact; } Fact* sensorHeight (void) { return &_sensorHeightFact; }
Fact* imageWidth (void) { return &_imageWidthFact; } Fact* imageWidth (void) { return &_imageWidthFact; }
...@@ -68,7 +56,6 @@ private: ...@@ -68,7 +56,6 @@ private:
QMap<QString, FactMetaData*> _metaDataMap; QMap<QString, FactMetaData*> _metaDataMap;
Fact _nameFact;
Fact _sensorWidthFact; Fact _sensorWidthFact;
Fact _sensorHeightFact; Fact _sensorHeightFact;
Fact _imageWidthFact; Fact _imageWidthFact;
...@@ -78,7 +65,6 @@ private: ...@@ -78,7 +65,6 @@ private:
Fact _fixedOrientationFact; Fact _fixedOrientationFact;
Fact _minTriggerIntervalFact; Fact _minTriggerIntervalFact;
static const char* _nameName;
static const char* _sensorWidthName; static const char* _sensorWidthName;
static const char* _sensorHeightName; static const char* _sensorHeightName;
static const char* _imageWidthName; static const char* _imageWidthName;
...@@ -87,14 +73,4 @@ private: ...@@ -87,14 +73,4 @@ private:
static const char* _landscapeName; static const char* _landscapeName;
static const char* _fixedOrientationName; static const char* _fixedOrientationName;
static const char* _minTriggerIntervalName; static const char* _minTriggerIntervalName;
static const char* _jsonNameKey;
static const char* _jsonSensorWidthKey;
static const char* _jsonSensorHeightKey;
static const char* _jsonImageWidthKey;
static const char* _jsonImageHeightKey;
static const char* _jsonFocalLengthKey;
static const char* _jsonLandscapeKey;
static const char* _jsonFixedOrientationKey;
static const char* _jsonMinTriggerIntervalKey;
}; };
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "SurveyMissionItem.h" #include "SurveyMissionItem.h"
#include "FixedWingLandingComplexItem.h" #include "FixedWingLandingComplexItem.h"
#include "StructureScanComplexItem.h" #include "StructureScanComplexItem.h"
#include "StructureScanComplexItem.h"
#include "JsonHelper.h" #include "JsonHelper.h"
#include "ParameterManager.h" #include "ParameterManager.h"
#include "QGroundControlQmlGlobal.h" #include "QGroundControlQmlGlobal.h"
...@@ -264,11 +265,15 @@ void MissionController::convertToKMLDocument(QDomDocument& document) ...@@ -264,11 +265,15 @@ void MissionController::convertToKMLDocument(QDomDocument& document)
{ {
QJsonObject missionJson; QJsonObject missionJson;
QmlObjectListModel* visualItems = new QmlObjectListModel(); QmlObjectListModel* visualItems = new QmlObjectListModel();
QList<MissionItem*> missionItens; QList<MissionItem*> missionItems;
QString error; QString error;
save(missionJson); save(missionJson);
_loadItemsFromJson(missionJson, visualItems, error); _loadItemsFromJson(missionJson, visualItems, error);
_convertToMissionItems(visualItems, missionItens, this); _convertToMissionItems(visualItems, missionItems, this);
if (missionItems.count() == 0) {
return;
}
float altitude = missionJson[_jsonPlannedHomePositionKey].toArray()[2].toDouble(); float altitude = missionJson[_jsonPlannedHomePositionKey].toArray()[2].toDouble();
...@@ -276,7 +281,7 @@ void MissionController::convertToKMLDocument(QDomDocument& document) ...@@ -276,7 +281,7 @@ void MissionController::convertToKMLDocument(QDomDocument& document)
QStringList coords; QStringList coords;
// Drop home position // Drop home position
bool dropPoint = true; bool dropPoint = true;
for(const auto& item : missionItens) { for(const auto& item : missionItems) {
if(dropPoint) { if(dropPoint) {
dropPoint = false; dropPoint = false;
continue; continue;
...@@ -655,6 +660,15 @@ bool MissionController::_loadJsonMissionFileV2(const QJsonObject& json, QmlObjec ...@@ -655,6 +660,15 @@ bool MissionController::_loadJsonMissionFileV2(const QJsonObject& json, QmlObjec
nextSequenceNumber = landingItem->lastSequenceNumber() + 1; nextSequenceNumber = landingItem->lastSequenceNumber() + 1;
qCDebug(MissionControllerLog) << "FW Landing Pattern load complete: nextSequenceNumber" << nextSequenceNumber; qCDebug(MissionControllerLog) << "FW Landing Pattern load complete: nextSequenceNumber" << nextSequenceNumber;
visualItems->append(landingItem); visualItems->append(landingItem);
} else if (complexItemType == StructureScanComplexItem::jsonComplexItemTypeValue) {
qCDebug(MissionControllerLog) << "Loading Structure Scan: nextSequenceNumber" << nextSequenceNumber;
StructureScanComplexItem* structureItem = new StructureScanComplexItem(_controllerVehicle, visualItems);
if (!structureItem->load(itemObject, nextSequenceNumber++, errorString)) {
return false;
}
nextSequenceNumber = structureItem->lastSequenceNumber() + 1;
qCDebug(MissionControllerLog) << "Structure Scan load complete: nextSequenceNumber" << nextSequenceNumber;
visualItems->append(structureItem);
} else if (complexItemType == MissionSettingsItem::jsonComplexItemTypeValue) { } else if (complexItemType == MissionSettingsItem::jsonComplexItemTypeValue) {
qCDebug(MissionControllerLog) << "Loading Mission Settings: nextSequenceNumber" << nextSequenceNumber; qCDebug(MissionControllerLog) << "Loading Mission Settings: nextSequenceNumber" << nextSequenceNumber;
MissionSettingsItem* settingsItem = new MissionSettingsItem(_controllerVehicle, visualItems); MissionSettingsItem* settingsItem = new MissionSettingsItem(_controllerVehicle, visualItems);
......
...@@ -21,10 +21,11 @@ ...@@ -21,10 +21,11 @@
QGC_LOGGING_CATEGORY(StructureScanComplexItemLog, "StructureScanComplexItemLog") QGC_LOGGING_CATEGORY(StructureScanComplexItemLog, "StructureScanComplexItemLog")
const char* StructureScanComplexItem::jsonComplexItemTypeValue = "StructureScan-WIP"; const char* StructureScanComplexItem::jsonComplexItemTypeValue = "StructureScan";
const char* StructureScanComplexItem::_altitudeFactName = "Altitude";
const char* StructureScanComplexItem::_altitudeFactName = "Altitude"; const char* StructureScanComplexItem::_layersFactName = "Layers";
const char* StructureScanComplexItem::_layersFactName = "Layers"; const char* StructureScanComplexItem::_jsonCameraCalcKey = "CameraCalc";
const char* StructureScanComplexItem::_jsonAltitudeRelativeKey = "altitudeRelative";
QMap<QString, FactMetaData*> StructureScanComplexItem::_metaDataMap; QMap<QString, FactMetaData*> StructureScanComplexItem::_metaDataMap;
...@@ -121,51 +122,24 @@ void StructureScanComplexItem::setDirty(bool dirty) ...@@ -121,51 +122,24 @@ void StructureScanComplexItem::setDirty(bool dirty)
void StructureScanComplexItem::save(QJsonArray& missionItems) void StructureScanComplexItem::save(QJsonArray& missionItems)
{ {
Q_UNUSED(missionItems);
#if 0
QJsonObject saveObject; QJsonObject saveObject;
saveObject[JsonHelper::jsonVersionKey] = 3; // Header
saveObject[JsonHelper::jsonVersionKey] = 1;
saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue; saveObject[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue; saveObject[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
saveObject[_jsonManualGridKey] = _manualGridFact.rawValue().toBool();
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitudeFact.rawValue().toBool();
saveObject[_jsonHoverAndCaptureKey] = _hoverAndCaptureFact.rawValue().toBool();
saveObject[_jsonRefly90DegreesKey] = _refly90Degrees;
saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble();
QJsonObject gridObject;
gridObject[_jsonGridAltitudeKey] = _gridAltitudeFact.rawValue().toDouble();
gridObject[_jsonGridAltitudeRelativeKey] = _gridAltitudeRelativeFact.rawValue().toBool();
gridObject[_jsonGridAngleKey] = _gridAngleFact.rawValue().toDouble();
gridObject[_jsonGridSpacingKey] = _gridSpacingFact.rawValue().toDouble();
gridObject[_jsonGridEntryLocationKey] = _gridEntryLocationFact.rawValue().toDouble();
gridObject[_jsonTurnaroundDistKey] = _turnaroundDistFact.rawValue().toDouble();
saveObject[_jsonGridObjectKey] = gridObject;
if (!_manualGridFact.rawValue().toBool()) {
QJsonObject cameraObject;
cameraObject[_jsonCameraNameKey] = _cameraFact.rawValue().toString();
cameraObject[_jsonCameraOrientationLandscapeKey] = _cameraOrientationLandscapeFact.rawValue().toBool();
cameraObject[_jsonCameraSensorWidthKey] = _cameraSensorWidthFact.rawValue().toDouble();
cameraObject[_jsonCameraSensorHeightKey] = _cameraSensorHeightFact.rawValue().toDouble();
cameraObject[_jsonCameraResolutionWidthKey] = _cameraResolutionWidthFact.rawValue().toDouble();
cameraObject[_jsonCameraResolutionHeightKey] = _cameraResolutionHeightFact.rawValue().toDouble();
cameraObject[_jsonCameraFocalLengthKey] = _cameraFocalLengthFact.rawValue().toDouble();
cameraObject[_jsonCameraMinTriggerIntervalKey] = _cameraMinTriggerInterval;
cameraObject[_jsonGroundResolutionKey] = _groundResolutionFact.rawValue().toDouble();
cameraObject[_jsonFrontalOverlapKey] = _frontalOverlapFact.rawValue().toInt();
cameraObject[_jsonSideOverlapKey] = _sideOverlapFact.rawValue().toInt();
saveObject[_jsonCameraObjectKey] = cameraObject;
}
// Polygon shape saveObject[_altitudeFactName] = _altitudeFact.rawValue().toDouble();
saveObject[_jsonAltitudeRelativeKey] = _altitudeRelative;
saveObject[_layersFactName] = _layersFact.rawValue().toDouble();
QJsonObject cameraCalcObject;
_cameraCalc.save(cameraCalcObject);
saveObject[_jsonCameraCalcKey] = cameraCalcObject;
_structurePolygon.saveToJson(saveObject); _structurePolygon.saveToJson(saveObject);
missionItems.append(saveObject); missionItems.append(saveObject);
#endif
} }
void StructureScanComplexItem::setSequenceNumber(int sequenceNumber) void StructureScanComplexItem::setSequenceNumber(int sequenceNumber)
...@@ -179,158 +153,50 @@ void StructureScanComplexItem::setSequenceNumber(int sequenceNumber) ...@@ -179,158 +153,50 @@ void StructureScanComplexItem::setSequenceNumber(int sequenceNumber)
bool StructureScanComplexItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString) bool StructureScanComplexItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
{ {
#if 0 QList<JsonHelper::KeyValidateInfo> keyInfoList = {
QJsonObject v2Object = complexObject;
// We need to pull version first to determine what validation/conversion needs to be performed.
QList<JsonHelper::KeyValidateInfo> versionKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true },
};
if (!JsonHelper::validateKeys(v2Object, versionKeyInfoList, errorString)) {
return false;
}
int version = v2Object[JsonHelper::jsonVersionKey].toInt();
if (version != 2 && version != 3) {
errorString = tr("%1 does not support this version of survey items").arg(qgcApp()->applicationName());
return false;
}
if (version == 2) {
// Convert to v3
if (v2Object.contains(VisualMissionItem::jsonTypeKey) && v2Object[VisualMissionItem::jsonTypeKey].toString() == QStringLiteral("survey")) {
v2Object[VisualMissionItem::jsonTypeKey] = VisualMissionItem::jsonTypeComplexItemValue;
v2Object[ComplexMissionItem::jsonComplexItemTypeKey] = jsonComplexItemTypeValue;
}
}
QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
{ JsonHelper::jsonVersionKey, QJsonValue::Double, true }, { JsonHelper::jsonVersionKey, QJsonValue::Double, true },
{ VisualMissionItem::jsonTypeKey, QJsonValue::String, true }, { VisualMissionItem::jsonTypeKey, QJsonValue::String, true },
{ ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true }, { ComplexMissionItem::jsonComplexItemTypeKey, QJsonValue::String, true },
{ QGCMapPolygon::jsonPolygonKey, QJsonValue::Array, true }, { QGCMapPolygon::jsonPolygonKey, QJsonValue::Array, true },
{ _jsonGridObjectKey, QJsonValue::Object, true }, { _altitudeFactName, QJsonValue::Double, true },
{ _jsonCameraObjectKey, QJsonValue::Object, false }, { _jsonAltitudeRelativeKey, QJsonValue::Bool, false },
{ _jsonCameraTriggerDistanceKey, QJsonValue::Double, true }, { _layersFactName, QJsonValue::Double, true },
{ _jsonManualGridKey, QJsonValue::Bool, true }, { _jsonCameraCalcKey, QJsonValue::Object, true },
{ _jsonFixedValueIsAltitudeKey, QJsonValue::Bool, true },
{ _jsonHoverAndCaptureKey, QJsonValue::Bool, false },
{ _jsonRefly90DegreesKey, QJsonValue::Bool, false },
}; };
if (!JsonHelper::validateKeys(v2Object, mainKeyInfoList, errorString)) { if (!JsonHelper::validateKeys(complexObject, keyInfoList, errorString)) {
return false; return false;
} }
QString itemType = v2Object[VisualMissionItem::jsonTypeKey].toString(); _structurePolygon.clear();
QString complexType = v2Object[ComplexMissionItem::jsonComplexItemTypeKey].toString();
QString itemType = complexObject[VisualMissionItem::jsonTypeKey].toString();
QString complexType = complexObject[ComplexMissionItem::jsonComplexItemTypeKey].toString();
if (itemType != VisualMissionItem::jsonTypeComplexItemValue || complexType != jsonComplexItemTypeValue) { 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); errorString = tr("%1 does not support loading this complex mission item type: %2:%3").arg(qgcApp()->applicationName()).arg(itemType).arg(complexType);
return false; return false;
} }
_ignoreRecalc = true; int version = complexObject[JsonHelper::jsonVersionKey].toInt();
if (version != 1) {
_structurePolygon.clear(); errorString = tr("Version %1 not supported").arg(version);
setSequenceNumber(sequenceNumber);
_manualGridFact.setRawValue (v2Object[_jsonManualGridKey].toBool(true));
_fixedValueIsAltitudeFact.setRawValue (v2Object[_jsonFixedValueIsAltitudeKey].toBool(true));
_gridAltitudeRelativeFact.setRawValue (v2Object[_jsonGridAltitudeRelativeKey].toBool(true));
_hoverAndCaptureFact.setRawValue (v2Object[_jsonHoverAndCaptureKey].toBool(false));
_refly90Degrees = v2Object[_jsonRefly90DegreesKey].toBool(false);
QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
{ _jsonGridAltitudeKey, QJsonValue::Double, true },
{ _jsonGridAltitudeRelativeKey, QJsonValue::Bool, true },
{ _jsonGridAngleKey, QJsonValue::Double, true },
{ _jsonGridSpacingKey, QJsonValue::Double, true },
{ _jsonGridEntryLocationKey, QJsonValue::Double, false },
{ _jsonTurnaroundDistKey, QJsonValue::Double, true },
};
QJsonObject gridObject = v2Object[_jsonGridObjectKey].toObject();
if (!JsonHelper::validateKeys(gridObject, gridKeyInfoList, errorString)) {
return false; return false;
} }
_gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (gridObject[_jsonGridSpacingKey].toDouble());
_turnaroundDistFact.setRawValue (gridObject[_jsonTurnaroundDistKey].toDouble());
_cameraTriggerDistanceFact.setRawValue (v2Object[_jsonCameraTriggerDistanceKey].toDouble());
if (gridObject.contains(_jsonGridEntryLocationKey)) {
_gridEntryLocationFact.setRawValue(gridObject[_jsonGridEntryLocationKey].toDouble());
} else {
_gridEntryLocationFact.setRawValue(_gridEntryLocationFact.rawDefaultValue());
}
if (!_manualGridFact.rawValue().toBool()) {
if (!v2Object.contains(_jsonCameraObjectKey)) {
errorString = tr("%1 but %2 object is missing").arg("manualGrid = false").arg("camera");
return false;
}
QJsonObject cameraObject = v2Object[_jsonCameraObjectKey].toObject(); setSequenceNumber(sequenceNumber);
// Older code had typo on "imageSideOverlap" incorrectly being "imageSizeOverlap"
QString incorrectImageSideOverlap = "imageSizeOverlap";
if (cameraObject.contains(incorrectImageSideOverlap)) {
cameraObject[_jsonSideOverlapKey] = cameraObject[incorrectImageSideOverlap];
cameraObject.remove(incorrectImageSideOverlap);
}
QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = { _altitudeFact.setRawValue (complexObject[_altitudeFactName].toDouble());
{ _jsonGroundResolutionKey, QJsonValue::Double, true }, _layersFact.setRawValue (complexObject[_layersFactName].toDouble());
{ _jsonFrontalOverlapKey, QJsonValue::Double, true }, _altitudeRelative = complexObject[_jsonAltitudeRelativeKey].toBool(true);
{ _jsonSideOverlapKey, QJsonValue::Double, true },
{ _jsonCameraSensorWidthKey, QJsonValue::Double, true },
{ _jsonCameraSensorHeightKey, QJsonValue::Double, true },
{ _jsonCameraResolutionWidthKey, QJsonValue::Double, true },
{ _jsonCameraResolutionHeightKey, QJsonValue::Double, true },
{ _jsonCameraFocalLengthKey, QJsonValue::Double, true },
{ _jsonCameraNameKey, QJsonValue::String, true },
{ _jsonCameraOrientationLandscapeKey, QJsonValue::Bool, true },
{ _jsonCameraMinTriggerIntervalKey, QJsonValue::Double, false },
};
if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList, errorString)) {
return false;
}
_cameraFact.setRawValue(cameraObject[_jsonCameraNameKey].toString()); if (!_cameraCalc.load(complexObject[_jsonCameraCalcKey].toObject(), errorString)) {
_cameraOrientationLandscapeFact.setRawValue(cameraObject[_jsonCameraOrientationLandscapeKey].toBool(true)); return false;
_groundResolutionFact.setRawValue (cameraObject[_jsonGroundResolutionKey].toDouble());
_frontalOverlapFact.setRawValue (cameraObject[_jsonFrontalOverlapKey].toInt());
_sideOverlapFact.setRawValue (cameraObject[_jsonSideOverlapKey].toInt());
_cameraSensorWidthFact.setRawValue (cameraObject[_jsonCameraSensorWidthKey].toDouble());
_cameraSensorHeightFact.setRawValue (cameraObject[_jsonCameraSensorHeightKey].toDouble());
_cameraResolutionWidthFact.setRawValue (cameraObject[_jsonCameraResolutionWidthKey].toDouble());
_cameraResolutionHeightFact.setRawValue (cameraObject[_jsonCameraResolutionHeightKey].toDouble());
_cameraFocalLengthFact.setRawValue (cameraObject[_jsonCameraFocalLengthKey].toDouble());
_cameraMinTriggerInterval = cameraObject[_jsonCameraMinTriggerIntervalKey].toDouble(0);
} }
if (!_structurePolygon.loadFromJson(complexObject, true /* required */, errorString)) {
// Polygon shape
/// Load a polygon from json
/// @param json Json object to load from
/// @param required true: no polygon in object will generate error
/// @param errorString Error string if return is false
/// @return true: success, false: failure (errorString set)
if (!_structurePolygon.loadFromJson(v2Object, true /* required */, errorString)) {
_structurePolygon.clear(); _structurePolygon.clear();
return false; return false;
} }
_ignoreRecalc = false;
_generateGrid();
return true; return true;
#else
Q_UNUSED(complexObject);
Q_UNUSED(sequenceNumber);
Q_UNUSED(errorString);
return false;
#endif
} }
void StructureScanComplexItem::_flightPathChanged(void) void StructureScanComplexItem::_flightPathChanged(void)
...@@ -380,6 +246,7 @@ void StructureScanComplexItem::appendMissionItems(QList<MissionItem*>& items, QO ...@@ -380,6 +246,7 @@ void StructureScanComplexItem::appendMissionItems(QList<MissionItem*>& items, QO
items.append(item); items.append(item);
for (int layer=0; layer<_layersFact.rawValue().toInt(); layer++) { for (int layer=0; layer<_layersFact.rawValue().toInt(); layer++) {
bool addTriggerStart = true;
double layerAltitude = baseAltitude + (layer * _cameraCalc.adjustedFootprintFrontal()->rawValue().toDouble()); double layerAltitude = baseAltitude + (layer * _cameraCalc.adjustedFootprintFrontal()->rawValue().toDouble());
for (int i=0; i<_flightPolygon.count(); i++) { for (int i=0; i<_flightPolygon.count(); i++) {
...@@ -399,6 +266,21 @@ void StructureScanComplexItem::appendMissionItems(QList<MissionItem*>& items, QO ...@@ -399,6 +266,21 @@ void StructureScanComplexItem::appendMissionItems(QList<MissionItem*>& items, QO
false, // isCurrentItem false, // isCurrentItem
missionItemParent); missionItemParent);
items.append(item); items.append(item);
if (addTriggerStart) {
addTriggerStart = false;
item = new MissionItem(seqNum++,
MAV_CMD_DO_SET_CAM_TRIGG_DIST,
MAV_FRAME_MISSION,
_cameraCalc.adjustedFootprintSide()->rawValue().toDouble(), // trigger distance
0, // shutter integration (ignore)
1, // trigger immediately when starting
0, 0, 0, 0, // param 4-7 unused
true, // autoContinue
false, // isCurrentItem
missionItemParent);
items.append(item);
}
} }
QGeoCoordinate vertexCoord = _flightPolygon.vertexCoordinate(0); QGeoCoordinate vertexCoord = _flightPolygon.vertexCoordinate(0);
...@@ -417,6 +299,18 @@ void StructureScanComplexItem::appendMissionItems(QList<MissionItem*>& items, QO ...@@ -417,6 +299,18 @@ void StructureScanComplexItem::appendMissionItems(QList<MissionItem*>& items, QO
false, // isCurrentItem false, // isCurrentItem
missionItemParent); missionItemParent);
items.append(item); items.append(item);
item = new MissionItem(seqNum++,
MAV_CMD_DO_SET_CAM_TRIGG_DIST,
MAV_FRAME_MISSION,
0, // stop triggering
0, // shutter integration (ignore)
0, // trigger immediately when starting
0, 0, 0, 0, // param 4-7 unused
true, // autoContinue
false, // isCurrentItem
missionItemParent);
items.append(item);
} }
} }
......
...@@ -129,6 +129,9 @@ private: ...@@ -129,6 +129,9 @@ private:
static const char* _altitudeFactName; static const char* _altitudeFactName;
static const char* _layersFactName; static const char* _layersFactName;
static const char* _jsonCameraCalcKey;
static const char* _jsonAltitudeRelativeKey;
}; };
#endif #endif
...@@ -60,7 +60,7 @@ Rectangle { ...@@ -60,7 +60,7 @@ Rectangle {
QGCLabel { QGCLabel {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("WARNING: WORK IN PROGRESS. DO NOT FLY. NO BUG REPORTS.") text: qsTr("WORK IN PROGRESS. CAREFUL!")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: qgcPal.warningText color: qgcPal.warningText
} }
......
...@@ -91,7 +91,7 @@ Item { ...@@ -91,7 +91,7 @@ Item {
borderWidth: 1 borderWidth: 1
borderColor: "black" borderColor: "black"
interiorColor: "green" interiorColor: "green"
interiorOpacity: 0.5 interiorOpacity: 0.25
} }
QGCMapPolygonVisuals { QGCMapPolygonVisuals {
......
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