Browse Source

Major rework of Survey ui

QGC4.4
Don Gagne 9 years ago
parent
commit
fd28bf0307
  1. 562
      src/MissionEditor/SurveyItemEditor.qml
  2. 67
      src/MissionManager/Survey.FactMetaData.json
  3. 253
      src/MissionManager/SurveyMissionItem.cc
  4. 67
      src/MissionManager/SurveyMissionItem.h

562
src/MissionEditor/SurveyItemEditor.qml

@ -1,6 +1,7 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QGroundControl 1.0 import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0 import QGroundControl.ScreenTools 1.0
@ -22,18 +23,50 @@ Rectangle {
//property var missionItem ///< Mission Item for editor //property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2 property real _margin: ScreenTools.defaultFontPixelWidth / 2
property int _cameraIndex: 1
property int cameraIndex: 1 readonly property int _gridTypeManual: 0
readonly property int _gridTypeCustomCamera: 1
readonly property int _gridTypeCamera: 2
Component.onCompleted: {
console.log("gridAltitude", missionItem.gridAltitude.value)
console.log("gridAltitudeRelative", missionItem.gridAltitudeRelative)
console.log("gridAngle", missionItem.gridAngle.value)
console.log("gridSpacing", missionItem.gridSpacing.value)
console.log("turnaroundDist", missionItem.turnaroundDist.value)
console.log("cameraTrigger", missionItem.cameraTrigger)
console.log("cameraTriggerDistance", missionItem.cameraTriggerDistance.value)
console.log("groundResolution", missionItem.groundResolution.value)
console.log("frontalOverlap", missionItem.frontalOverlap.value)
console.log("sideOverlap", missionItem.sideOverlap.value)
console.log("cameraSensorWidth", missionItem.cameraSensorWidth.value)
console.log("cameraSensorHeight", missionItem.cameraSensorHeight.value)
console.log("cameraResolutionWidth", missionItem.cameraResolutionWidth.value)
console.log("cameraResolutionHeight", missionItem.cameraResolutionHeight.value)
console.log("cameraFocalLength", missionItem.cameraFocalLength.value)
console.log("fixedValueIsAltitude", missionItem.fixedValueIsAltitude)
console.log("cameraOrientationLandscape", missionItem.cameraOrientationLandscape)
console.log("manualGrid", missionItem.manualGrid)
console.log("camera", missionItem.camera)
}
ListModel { ListModel {
id: cameraModelList id: cameraModelList
Component.onCompleted: {
cameraModelList.setProperty(_gridTypeCustomCamera, "sensorWidth", missionItem.cameraSensorWidth.rawValue)
cameraModelList.setProperty(_gridTypeCustomCamera, "sensorHeight", missionItem.cameraSensorHeight.rawValue)
cameraModelList.setProperty(_gridTypeCustomCamera, "imageWidth", missionItem.cameraResolutionWidth.rawValue)
cameraModelList.setProperty(_gridTypeCustomCamera, "imageHeight", missionItem.cameraResolutionHeight.rawValue)
cameraModelList.setProperty(_gridTypeCustomCamera, "focalLength", missionItem.cameraFocalLength.rawValue)
}
ListElement { ListElement {
text: qsTr("Custom") text: qsTr("Manual Grid (no camera specs)")
sensorWidth: 0 }
sensorHeight: 0 ListElement {
imageWidth: 0 text: qsTr("Custom Camera Grid")
imageHeight: 0
focalLength: 0
} }
ListElement { ListElement {
text: qsTr("Sony ILCE-QX1") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications text: qsTr("Sony ILCE-QX1") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications
@ -78,70 +111,76 @@ Rectangle {
} }
function recalcFromCameraValues() { function recalcFromCameraValues() {
var focalLength = cameraModelList.get(cameraIndex).focalLength var focalLength = missionItem.cameraFocalLength.rawValue
var sensorWidth = cameraModelList.get(cameraIndex).sensorWidth var sensorWidth = missionItem.cameraSensorWidth.rawValue
var sensorHeight = cameraModelList.get(cameraIndex).sensorHeight var sensorHeight = missionItem.cameraSensorHeight.rawValue
var imageWidth = cameraModelList.get(cameraIndex).imageWidth var imageWidth = missionItem.cameraResolutionWidth.rawValue
var imageHeight = cameraModelList.get(cameraIndex).imageHeight var imageHeight = missionItem.cameraResolutionHeight.rawValue
var gsd = Number(gsdField.text) var altitude = missionItem.gridAltitude.rawValue
var frontalOverlap = Number(frontalOverlapField.text) var groundResolution = missionItem.groundResolution.rawValue
var sideOverlap = Number(sideOverlapField.text) var frontalOverlap = missionItem.frontalOverlap.rawValue
var sideOverlap = missionItem.sideOverlap.rawValue
if (focalLength <= 0.0 || sensorWidth <= 0.0 || sensorHeight <= 0.0 || imageWidth < 0 || imageHeight < 0 || gsd < 0.0 || frontalOverlap < 0 || sideOverlap < 0) {
missionItem.gridAltitude.rawValue = 0 if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || groundResolution <= 0) {
missionItem.gridSpacing.rawValue = 0
missionItem.cameraTriggerDistance.rawValue = 0
return return
} }
var altitude
var imageSizeSideGround //size in side (non flying) direction of the image on the ground 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 imageSizeFrontGround //size in front (flying) direction of the image on the ground
var gridSpacing var gridSpacing
var cameraTriggerDistance var cameraTriggerDistance
altitude = (imageWidth * gsd * focalLength) / (sensorWidth * 100) if (missionItem.fixedValueIsAltitude) {
groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
} else {
altitude = (imageWidth * groundResolution * focalLength) / (sensorWidth * 100)
}
if (cameraOrientationLandscape.checked) { if (cameraOrientationLandscape.checked) {
imageSizeSideGround = (imageWidth * gsd) / 100 imageSizeSideGround = (imageWidth * groundResolution) / 100
imageSizeFrontGround = (imageHeight * gsd) / 100 imageSizeFrontGround = (imageHeight * groundResolution) / 100
} else { } else {
imageSizeSideGround = (imageHeight * gsd) / 100 imageSizeSideGround = (imageHeight * groundResolution) / 100
imageSizeFrontGround = (imageWidth * gsd) / 100 imageSizeFrontGround = (imageWidth * groundResolution) / 100
} }
gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 ) gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 )
cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 ) cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 )
if (missionItem.fixedValueIsAltitude) {
missionItem.groundResolution.rawValue = groundResolution
} else {
missionItem.gridAltitude.rawValue = altitude missionItem.gridAltitude.rawValue = altitude
}
missionItem.gridSpacing.rawValue = gridSpacing missionItem.gridSpacing.rawValue = gridSpacing
missionItem.cameraTriggerDistance.rawValue = cameraTriggerDistance missionItem.cameraTriggerDistance.rawValue = cameraTriggerDistance
} }
/*
function recalcFromMissionValues() { function recalcFromMissionValues() {
var focalLength = cameraModelList.get(cameraIndex).focalLength var focalLength = missionItem.cameraFocalLength.rawValue
var sensorWidth = cameraModelList.get(cameraIndex).sensorWidth var sensorWidth = missionItem.cameraSensorWidth.rawValue
var sensorHeight = cameraModelList.get(cameraIndex).sensorHeight var sensorHeight = missionItem.cameraSensorHeight.rawValue
var imageWidth = cameraModelList.get(cameraIndex).imageWidth var imageWidth = missionItem.cameraResolutionWidth.rawValue
var imageHeight = cameraModelList.get(cameraIndex).imageHeight var imageHeight = missionItem.cameraResolutionHeight.rawValue
var altitude = missionItem.gridAltitude.rawValue var altitude = missionItem.gridAltitude.rawValue
var gridSpacing = missionItem.gridSpacing.rawValue var gridSpacing = missionItem.gridSpacing.rawValue
var cameraTriggerDistance = missionItem.cameraTriggerDistance.rawValue var cameraTriggerDistance = missionItem.cameraTriggerDistance.rawValue
if (focalLength <= 0.0 || sensorWidth <= 0.0 || sensorHeight <= 0.0 || imageWidth < 0 || imageHeight < 0 || altitude < 0.0 || gridSpacing < 0.0 || cameraTriggerDistance < 0.0) { if (focalLength <= 0.0 || sensorWidth <= 0.0 || sensorHeight <= 0.0 || imageWidth < 0 || imageHeight < 0 || altitude < 0.0 || gridSpacing < 0.0 || cameraTriggerDistance < 0.0) {
gsdField.text = "0.0" missionItem.groundResolution.rawValue = 0
sideOverlapField.text = "0" missionItem.sideOverlap = 0
frontalOverlapField.text = "0" missionItem.frontalOverlap = 0
return return
} }
var gsd var groundResolution
var imageSizeSideGround //size in side (non flying) direction of the image on the ground 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 imageSizeFrontGround //size in front (flying) direction of the image on the ground
gsd = (altitude * sensorWidth * 100) / (imageWidth * focalLength) groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
if (cameraOrientationLandscape.checked) { if (cameraOrientationLandscape.checked) {
imageSizeSideGround = (imageWidth * gsd) / 100 imageSizeSideGround = (imageWidth * gsd) / 100
@ -154,10 +193,11 @@ Rectangle {
var sideOverlap = (imageSizeSideGround == 0 ? 0 : 100 - (gridSpacing*100 / imageSizeSideGround)) var sideOverlap = (imageSizeSideGround == 0 ? 0 : 100 - (gridSpacing*100 / imageSizeSideGround))
var frontOverlap = (imageSizeFrontGround == 0 ? 0 : 100 - (cameraTriggerDistance*100 / imageSizeFrontGround)) var frontOverlap = (imageSizeFrontGround == 0 ? 0 : 100 - (cameraTriggerDistance*100 / imageSizeFrontGround))
gsdField.text = gsd.toFixed(1) missionItem.groundResolution.rawValue = groundResolution
sideOverlapField.text = sideOverlap.toFixed(0) missionItem.sideOverlap.rawValue = sideOverlap
frontalOverlapField.text = frontOverlap.toFixed(0) missionItem.frontalOverlap.rawValue = frontOverlap
} }
*/
function polygonCaptureStarted() { function polygonCaptureStarted() {
missionItem.clearPolygon() missionItem.clearPolygon()
@ -176,14 +216,41 @@ Rectangle {
function polygonAdjustStarted() { } function polygonAdjustStarted() { }
function polygonAdjustFinished() { } function polygonAdjustFinished() { }
property bool _noCameraValueRecalc: false ///< Prevents uneeded recalcs
Connections {
target: missionItem
onCameraValueChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && !_noCameraValueRecalc) {
recalcFromCameraValues()
}
}
}
Connections {
target: missionItem.gridAltitude
onValueChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && missionItem.fixedValueIsAltitude && !_noCameraValueRecalc) {
recalcFromCameraValues()
}
}
}
QGCPalette { id: qgcPal; colorGroupEnabled: true } QGCPalette { id: qgcPal; colorGroupEnabled: true }
ExclusiveGroup { ExclusiveGroup {
id: cameraOrientationGroup id: cameraOrientationGroup
onCurrentChanged: { onCurrentChanged: {
recalcFromMissionValues() if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
recalcFromCameraValues()
} }
} }
}
ExclusiveGroup { id: fixedValueGroup }
Column { Column {
id: editorColumn id: editorColumn
@ -198,97 +265,68 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
font.pointSize: ScreenTools.smallFontPointSize font.pointSize: ScreenTools.smallFontPointSize
text: qsTr("Create a flight path to fully cover a polygonal area with a camera.") text: gridTypeCombo.currentIndex == 0 ?
qsTr("Create a flight path which covers a polygonal area by specifying all grid parameters.") :
qsTr("Create a flight path which fully covers a polygonal area using camera specifications.")
} }
Repeater { QGCLabel { text: qsTr("Camera:") }
model: [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
Item { Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: textField.height height: 1
color: qgcPal.text
QGCLabel {
anchors.baseline: textField.baseline
anchors.left: parent.left
text: modelData.name + ":"
} }
FactTextField { QGCComboBox {
id: textField id: gridTypeCombo
anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
width: _editFieldWidth model: cameraModelList
showUnits: true currentIndex: -1
fact: modelData
onEditingFinished: recalcFromMissionValues()
validator: DoubleValidator{bottom:0.0; decimals:2}
}
}
}
QGCCheckBox { Component.onCompleted: {
anchors.left: parent.left if (missionItem.manualGrid) {
text: qsTr("Relative altitude") gridTypeCombo.currentIndex = _gridTypeManual
checked: missionItem.gridAltitudeRelative } else {
onClicked: missionItem.gridAltitudeRelative = checked var index = gridTypeCombo.find(missionItem.camera)
if (index == -1) {
console.log("Couldn't find camera", missionItem.camera)
gridTypeCombo.currentIndex = _gridTypeManual
} else {
gridTypeCombo.currentIndex = index
} }
Grid {
columns: 2
columnSpacing: ScreenTools.defaultFontPixelWidth
rowSpacing: _margin
verticalItemAlignment: Grid.AlignVCenter
QGCLabel {
text: qsTr("GSD:")
width: _editFieldWidth
} }
QGCTextField {
id: gsdField
width: _editFieldWidth
unitsLabel: "cm/px"
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: DoubleValidator{bottom:0.0; decimals:2}
} }
QGCLabel { text: qsTr("Frontal Overlap:") } onActivated: {
QGCTextField { if (index == _gridTypeManual) {
id: frontalOverlapField missionItem.manualGrid = true
width: _editFieldWidth } else {
unitsLabel: "%" missionItem.manualGrid = false
showUnits: true missionItem.camera = gridTypeCombo.textAt(index)
onEditingFinished: recalcFromCameraValues() _noCameraValueRecalc = true
validator: IntValidator {bottom:0} missionItem.cameraSensorWidth.rawValue = cameraModelList.get(index).sensorWidth
missionItem.cameraSensorHeight.rawValue = cameraModelList.get(index).sensorHeight
missionItem.cameraResolutionWidth.rawValue = cameraModelList.get(index).imageWidth
missionItem.cameraResolutionHeight.rawValue = cameraModelList.get(index).imageHeight
missionItem.cameraFocalLength.rawValue = cameraModelList.get(index).focalLength
_noCameraValueRecalc = false
recalcFromCameraValues()
} }
QGCLabel { text: qsTr("Side Overlap:") }
QGCTextField {
id: sideOverlapField
width: _editFieldWidth
unitsLabel: "%"
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: IntValidator {bottom:0}
} }
Component.onCompleted: recalcFromMissionValues()
} }
QGCLabel { text: qsTr("Camera:") } // Camera based grid ui
Column {
Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: 1 spacing: _margin
color: qgcPal.text visible: gridTypeCombo.currentIndex != _gridTypeManual
}
Grid { Row {
columns: 2 spacing: _margin
spacing: ScreenTools.defaultFontPixelWidth
verticalItemAlignment: Grid.AlignVCenter
QGCRadioButton { QGCRadioButton {
id: cameraOrientationLandscape id: cameraOrientationLandscape
@ -303,201 +341,215 @@ Rectangle {
text: "Portrait" text: "Portrait"
exclusiveGroup: cameraOrientationGroup exclusiveGroup: cameraOrientationGroup
} }
QGCCheckBox {
id: cameraTrigger
width: _editFieldWidth
text: qsTr("Trigger:")
checked: missionItem.cameraTrigger
onClicked: missionItem.cameraTrigger = checked
}
FactTextField {
width: _editFieldWidth
showUnits: true
fact: missionItem.cameraTriggerDistance
enabled: missionItem.cameraTrigger
onEditingFinished: recalcFromMissionValues()
validator: DoubleValidator{bottom:0.0; decimals:2}
}
} }
Component {
id: cameraFields
QGCViewDialog {
Column { Column {
id: dialogColumn
anchors.margins: _margin
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
spacing: _margin * 5 spacing: _margin
visible: gridTypeCombo.currentIndex == _gridTypeCustomCamera
Row { GridLayout {
spacing: ScreenTools.defaultFontPixelWidth columns: 3
columnSpacing: _margin
rowSpacing: _margin
QGCLabel { property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10
id: selectCameraModelText
text: qsTr("Select Camera Model:")
}
QGCComboBox { QGCLabel { }
id: cameraModelCombo QGCLabel { text: qsTr("Width") }
model: cameraModelList QGCLabel { text: qsTr("Height") }
width: dialogColumn.width - selectCameraModelText.width - ScreenTools.defaultFontPixelWidth
onActivated: { QGCLabel { text: qsTr("Sensor:") }
cameraIndex = index FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraSensorWidth
}
FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraSensorHeight
} }
Component.onCompleted: { QGCLabel { text: qsTr("Image:") }
var index = cameraIndex FactTextField {
if (index === -1) { Layout.preferredWidth: parent._fieldWidth
console.warn("Active camera model name not in combo", cameraIndex) fact: missionItem.cameraResolutionWidth
} else {
cameraModelCombo.currentIndex = index
} }
FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraResolutionHeight
} }
} }
FactTextFieldRow {
spacing: _margin
fact: missionItem.cameraFocalLength
} }
} // Column - custom camera
Grid { QGCLabel { text: qsTr("Image Overlap") }
columns: 2
spacing: ScreenTools.defaultFontPixelWidth
verticalItemAlignment: Grid.AlignVCenter
QGCLabel { text: qsTr("Sensor Width:") } Row {
QGCTextField { spacing: _margin
id: sensorWidthField
unitsLabel: "mm" Item {
showUnits: true width: ScreenTools.defaultFontPixelWidth * 2
text: cameraModelList.get(cameraIndex).sensorWidth.toFixed(2) height: 1
readOnly: cameraIndex != 0
enabled: cameraIndex == 0
validator: DoubleValidator{bottom:0.0; decimals:2}
onEditingFinished: {
if (cameraIndex == 0) {
cameraModelList.setProperty(cameraIndex, "sensorWidth", Number(text))
}
}
} }
QGCLabel { text: qsTr("Sensor Height:") } QGCLabel {
QGCTextField { anchors.baseline: frontalOverlapField.baseline
id: sensorHeightField text: qsTr("Frontal:")
unitsLabel: "mm"
showUnits: true
text: cameraModelList.get(cameraIndex).sensorHeight.toFixed(2)
readOnly: cameraIndex != 0
enabled: cameraIndex == 0
validator: DoubleValidator{bottom:0.0; decimals:2}
onEditingFinished: {
if (cameraIndex == 0) {
cameraModelList.setProperty(cameraIndex, "sensorHeight", Number(text))
} }
FactTextField {
id: frontalOverlapField
width: ScreenTools.defaultFontPixelWidth * 7
fact: missionItem.frontalOverlap
} }
QGCLabel {
anchors.baseline: frontalOverlapField.baseline
text: qsTr("Side:")
} }
QGCLabel { text: qsTr("Image Width:") } FactTextField {
QGCTextField { width: frontalOverlapField.width
id: imageWidthField fact: missionItem.sideOverlap
unitsLabel: "px"
showUnits: true
text: cameraModelList.get(cameraIndex).imageWidth.toFixed(0)
readOnly: cameraIndex != 0
enabled: cameraIndex == 0
validator: IntValidator {bottom:0}
onEditingFinished: {
if (cameraIndex == 0) {
cameraModelList.setProperty(cameraIndex, "imageWidth", Number(text))
} }
} }
QGCLabel { text: qsTr("Grid:") }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
} }
QGCLabel { text: qsTr("Image Height:") } FactTextFieldGrid {
QGCTextField { anchors.left: parent.left
id: imageHeightField anchors.right: parent.right
unitsLabel: "px" columnSpacing: _margin
showUnits: true rowSpacing: _margin
text: cameraModelList.get(cameraIndex).imageHeight.toFixed(0) factList: [ missionItem.gridAngle, missionItem.turnaroundDist ]
readOnly: cameraIndex != 0
enabled: cameraIndex == 0
validator: IntValidator {bottom:0}
onEditingFinished: {
if (cameraIndex == 0) {
cameraModelList.setProperty(cameraIndex, "imageHeight", Number(text))
} }
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
font.pointSize: ScreenTools.smallFontPointSize
text: qsTr("Which value would you like to keep constant as you adjust other settings:")
} }
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCRadioButton {
id: fixedAltitudeRadio
anchors.baseline: gridAltitudeField.baseline
text: qsTr("Altitude:")
checked: missionItem.fixedValueIsAltitude
exclusiveGroup: fixedValueGroup
onClicked: missionItem.fixedValueIsAltitude = true
} }
QGCLabel { text: qsTr("Focal Length:") } FactTextField {
QGCTextField { id: gridAltitudeField
id: focalLengthField Layout.fillWidth: true
unitsLabel: "mm" fact: missionItem.gridAltitude
showUnits: true enabled: fixedAltitudeRadio.checked
text: cameraModelList.get(cameraIndex).focalLength.toFixed(2)
readOnly: cameraIndex != 0
enabled: cameraIndex == 0
validator: DoubleValidator{bottom:0.0; decimals:2}
onEditingFinished: {
if (cameraIndex == 0) {
cameraModelList.setProperty(cameraIndex, "focalLength", Number(text))
} }
} }
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCRadioButton {
id: fixedGroundResolutionRadio
anchors.baseline: groundResolutionField.baseline
text: qsTr("Ground res:")
checked: !missionItem.fixedValueIsAltitude
exclusiveGroup: fixedValueGroup
onClicked: missionItem.fixedValueIsAltitude = false
} }
FactTextField {
id: groundResolutionField
Layout.fillWidth: true
fact: missionItem.groundResolution
enabled: fixedGroundResolutionRadio.checked
} }
} }
function accept() {
hideDialog()
recalcFromCameraValues()
} }
}//QGCViewDialog
}//Component
// Manual grid ui
Column { Column {
spacing: ScreenTools.defaultFontPixelHeight*0.01 anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: gridTypeCombo.currentIndex == _gridTypeManual
Row { QGCLabel { text: qsTr("Grid:") }
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel { text: qsTr("Model:") } Rectangle {
QGCLabel { text: cameraModelList.get(cameraIndex).text } anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
} }
Grid { FactTextFieldGrid {
columns: 2 anchors.left: parent.left
columnSpacing: ScreenTools.defaultFontPixelWidth anchors.right: parent.right
rowSpacing: ScreenTools.defaultFontPixelHeight*0.01 columnSpacing: _margin
rowSpacing: _margin
QGCLabel { factList: [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
text: qsTr("Sensor Size:")
width: _editFieldWidth
} }
QGCLabel {
text: cameraModelList.get(cameraIndex).sensorWidth.toFixed(2) + qsTr(" x ") + cameraModelList.get(cameraIndex).sensorHeight.toFixed(2) QGCCheckBox {
width: _editFieldWidth anchors.left: parent.left
text: qsTr("Relative altitude")
checked: missionItem.gridAltitudeRelative
onClicked: missionItem.gridAltitudeRelative = checked
} }
QGCLabel { text: qsTr("Image Size:") } QGCLabel { text: qsTr("Camera:") }
QGCLabel { text: cameraModelList.get(cameraIndex).imageWidth.toFixed(0) + qsTr(" x ") + cameraModelList.get(cameraIndex).imageHeight.toFixed(0) }
QGCLabel { text: qsTr("Focal length:") } Rectangle {
QGCLabel { text: cameraModelList.get(cameraIndex).focalLength.toFixed(2) } anchors.left: parent.left
} anchors.right: parent.right
height: 1
color: qgcPal.text
} }
QGCButton { RowLayout {
id: cameraModelChange anchors.left: parent.left
text: qsTr("Change") anchors.right: parent.right
spacing: _margin
onClicked: { QGCCheckBox {
qgcView.showDialog(cameraFields, qsTr("Set Camera Model"), qgcView.showDialogDefaultWidth, StandardButton.Save) id: cameraTrigger
} anchors.baseline: cameraTriggerDistanceField.baseline
text: qsTr("Trigger Distance:")
checked: missionItem.cameraTrigger
onClicked: missionItem.cameraTrigger = checked
} }
FactTextField {
id: cameraTriggerDistanceField
Layout.fillWidth: true
fact: missionItem.cameraTriggerDistance
enabled: missionItem.cameraTrigger
}
}
}
QGCLabel { text: qsTr("Polygon:") } QGCLabel { text: qsTr("Polygon:") }

67
src/MissionManager/Survey.FactMetaData.json

@ -18,20 +18,85 @@
"shortDescription": "Amount of spacing in between parallel grid lines.", "shortDescription": "Amount of spacing in between parallel grid lines.",
"type": "double", "type": "double",
"decimalPlaces": 2, "decimalPlaces": 2,
"min": 0.1,
"units": "m" "units": "m"
}, },
{ {
"name": "Turnaround dist.", "name": "Turnaround dist",
"shortDescription": "Amount of additional distance to add outside the grid area for vehicle turnaround.", "shortDescription": "Amount of additional distance to add outside the grid area for vehicle turnaround.",
"type": "double", "type": "double",
"decimalPlaces": 2, "decimalPlaces": 2,
"min": 0,
"units": "m" "units": "m"
}, },
{ {
"name": "Ground resolution",
"shortDescription": "Resolution of image in relationship to ground distance.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "cm/px"
},
{
"name": "Frontal overlap",
"shortDescription": "Amount of overlap between images in the forward facing direction.",
"type": "double",
"decimalPlaces": 0,
"max": 75,
"units": "%"
},
{
"name": "Side overlap",
"shortDescription": "Amount of overlap between images in the side facing direction.",
"type": "double",
"decimalPlaces": 0,
"max": 75,
"units": "%"
},
{
"name": "Camera sensor width",
"shortDescription": "Amount of overlap between images in the side facing direction.",
"type": "double",
"decimalPlaces": 2,
"min": 1,
"units": "mm"
},
{
"name": "Camera sensor height",
"shortDescription": "Amount of overlap between images in the side facing direction.",
"type": "double",
"decimalPlaces": 2,
"min": 1,
"units": "mm"
},
{
"name": "Camera resolution width",
"shortDescription": "Amount of overlap between images in the side facing direction.",
"type": "uint32",
"min": 1,
"units": "px"
},
{
"name": "Camera resolution height",
"shortDescription": "Amount of overlap between images in the side facing direction.",
"type": "uint32",
"min": 1,
"units": "px"
},
{
"name": "Focal length",
"shortDescription": "Amount of overlap between images in the side facing direction.",
"type": "double",
"decimalPlaces": 1,
"min": 1,
"units": "mm"
},
{
"name": "Camera trigger distance", "name": "Camera trigger distance",
"shortDescription": "Distance between each triggering of the camera.", "shortDescription": "Distance between each triggering of the camera.",
"type": "double", "type": "double",
"decimalPlaces": 2, "decimalPlaces": 2,
"min": 0.1,
"units": "m" "units": "m"
} }
] ]

253
src/MissionManager/SurveyMissionItem.cc

@ -18,21 +18,43 @@
QGC_LOGGING_CATEGORY(SurveyMissionItemLog, "SurveyMissionItemLog") QGC_LOGGING_CATEGORY(SurveyMissionItemLog, "SurveyMissionItemLog")
const char* SurveyMissionItem::_jsonTypeKey = "type"; const char* SurveyMissionItem::_jsonTypeKey = "type";
const char* SurveyMissionItem::_jsonPolygonKey = "polygon"; const char* SurveyMissionItem::_jsonPolygonObjectKey = "polygon";
const char* SurveyMissionItem::_jsonIdKey = "id"; const char* SurveyMissionItem::_jsonIdKey = "id";
const char* SurveyMissionItem::_jsonGridAltitudeKey = "gridAltitude"; const char* SurveyMissionItem::_jsonGridObjectKey = "grid";
const char* SurveyMissionItem::_jsonGridAltitudeRelativeKey = "gridAltitudeRelative"; const char* SurveyMissionItem::_jsonGridAltitudeKey = "altitude";
const char* SurveyMissionItem::_jsonGridAngleKey = "gridAngle"; const char* SurveyMissionItem::_jsonGridAltitudeRelativeKey = "relativeAltitude";
const char* SurveyMissionItem::_jsonGridSpacingKey = "gridSpacing"; const char* SurveyMissionItem::_jsonGridAngleKey = "angle";
const char* SurveyMissionItem::_jsonTurnaroundDistKey = "turnaroundDist"; const char* SurveyMissionItem::_jsonGridSpacingKey = "spacing";
const char* SurveyMissionItem::_jsonTurnaroundDistKey = "turnAroundDistance";
const char* SurveyMissionItem::_jsonCameraTriggerKey = "cameraTrigger"; const char* SurveyMissionItem::_jsonCameraTriggerKey = "cameraTrigger";
const char* SurveyMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance"; const char* SurveyMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance";
const char* SurveyMissionItem::_jsonGroundResolutionKey = "groundResolution";
const char* SurveyMissionItem::_jsonFrontalOverlapKey = "imageFrontalOverlap";
const char* SurveyMissionItem::_jsonSideOverlapKey = "imageSizeOverlap";
const char* SurveyMissionItem::_jsonCameraSensorWidthKey = "sensorWidth";
const char* SurveyMissionItem::_jsonCameraSensorHeightKey = "sensorHeight";
const char* SurveyMissionItem::_jsonCameraResolutionWidthKey = "resolutionWidth";
const char* SurveyMissionItem::_jsonCameraResolutionHeightKey = "resolutionHeight";
const char* SurveyMissionItem::_jsonCameraFocalLengthKey = "focalLength";
const char* SurveyMissionItem::_jsonCameraObjectKey = "camera";
const char* SurveyMissionItem::_jsonCameraNameKey = "name";
const char* SurveyMissionItem::_jsonManualGridKey = "manualGrid";
const char* SurveyMissionItem::_jsonCameraOrientationLandscapeKey = "orientationLandscape";
const char* SurveyMissionItem::_jsonFixedValueIsAltitudeKey = "fixedValueIsAltitude";
const char* SurveyMissionItem::_gridAltitudeFactName = "Altitude"; const char* SurveyMissionItem::_gridAltitudeFactName = "Altitude";
const char* SurveyMissionItem::_gridAngleFactName = "Grid angle"; const char* SurveyMissionItem::_gridAngleFactName = "Grid angle";
const char* SurveyMissionItem::_gridSpacingFactName = "Grid spacing"; const char* SurveyMissionItem::_gridSpacingFactName = "Grid spacing";
const char* SurveyMissionItem::_turnaroundDistFactName = "Turnaround dist."; const char* SurveyMissionItem::_turnaroundDistFactName = "Turnaround dist";
const char* SurveyMissionItem::_cameraTriggerDistanceFactName = "Camera trigger distance"; const char* SurveyMissionItem::_cameraTriggerDistanceFactName = "Camera trigger distance";
const char* SurveyMissionItem::_groundResolutionFactName = "Ground resolution";
const char* SurveyMissionItem::_frontalOverlapFactName = "Frontal overlap";
const char* SurveyMissionItem::_sideOverlapFactName = "Side overlap";
const char* SurveyMissionItem::_cameraSensorWidthFactName = "Camera sensor width";
const char* SurveyMissionItem::_cameraSensorHeightFactName = "Camera sensor height";
const char* SurveyMissionItem::_cameraResolutionWidthFactName = "Camera resolution width";
const char* SurveyMissionItem::_cameraResolutionHeightFactName = "Camera resolution height";
const char* SurveyMissionItem::_cameraFocalLengthFactName = "Focal length";
const char* SurveyMissionItem::_complexType = "survey"; const char* SurveyMissionItem::_complexType = "survey";
@ -44,6 +66,9 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
, _dirty(false) , _dirty(false)
, _cameraTrigger(true) , _cameraTrigger(true)
, _gridAltitudeRelative(true) , _gridAltitudeRelative(true)
, _manualGrid(true)
, _cameraOrientationLandscape(true)
, _fixedValueIsAltitude(false)
, _surveyDistance(0.0) , _surveyDistance(0.0)
, _cameraShots(0) , _cameraShots(0)
, _coveredArea(0.0) , _coveredArea(0.0)
@ -52,21 +77,46 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
, _gridSpacingFact (0, _gridSpacingFactName, FactMetaData::valueTypeDouble) , _gridSpacingFact (0, _gridSpacingFactName, FactMetaData::valueTypeDouble)
, _turnaroundDistFact (0, _turnaroundDistFactName, FactMetaData::valueTypeDouble) , _turnaroundDistFact (0, _turnaroundDistFactName, FactMetaData::valueTypeDouble)
, _cameraTriggerDistanceFact (0, _cameraTriggerDistanceFactName, FactMetaData::valueTypeDouble) , _cameraTriggerDistanceFact (0, _cameraTriggerDistanceFactName, FactMetaData::valueTypeDouble)
, _groundResolutionFact (0, _groundResolutionFactName, FactMetaData::valueTypeDouble)
, _frontalOverlapFact (0, _frontalOverlapFactName, FactMetaData::valueTypeDouble)
, _sideOverlapFact (0, _sideOverlapFactName, FactMetaData::valueTypeDouble)
, _cameraSensorWidthFact (0, _cameraSensorWidthFactName, FactMetaData::valueTypeDouble)
, _cameraSensorHeightFact (0, _cameraSensorHeightFactName, FactMetaData::valueTypeDouble)
, _cameraResolutionWidthFact (0, _cameraResolutionWidthFactName, FactMetaData::valueTypeUint32)
, _cameraResolutionHeightFact (0, _cameraResolutionHeightFactName, FactMetaData::valueTypeUint32)
, _cameraFocalLengthFact (0, _cameraFocalLengthFactName, FactMetaData::valueTypeDouble)
{ {
if (_metaDataMap.isEmpty()) { if (_metaDataMap.isEmpty()) {
_metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/Survey.FactMetaData.json"), NULL /* metaDataParent */); _metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/Survey.FactMetaData.json"), NULL /* metaDataParent */);
} }
_gridAltitudeFact.setRawValue(50); _gridAltitudeFact.setRawValue(50);
_gridSpacingFact.setRawValue(10); _gridSpacingFact.setRawValue(30);
_turnaroundDistFact.setRawValue(60); _turnaroundDistFact.setRawValue(_vehicle->multiRotor() ? 0 : 60);
_cameraTriggerDistanceFact.setRawValue(25); _cameraTriggerDistanceFact.setRawValue(25);
_groundResolutionFact.setRawValue(3);
_frontalOverlapFact.setRawValue(10);
_sideOverlapFact.setRawValue(10);
_cameraSensorWidthFact.setRawValue(6.17);
_cameraSensorHeightFact.setRawValue(4.55);
_cameraResolutionWidthFact.setRawValue(4000);
_cameraResolutionHeightFact.setRawValue(3000);
_cameraFocalLengthFact.setRawValue(4.5);
_gridAltitudeFact.setMetaData(_metaDataMap[_gridAltitudeFactName]); _gridAltitudeFact.setMetaData(_metaDataMap[_gridAltitudeFactName]);
_gridAngleFact.setMetaData(_metaDataMap[_gridAngleFactName]); _gridAngleFact.setMetaData(_metaDataMap[_gridAngleFactName]);
_gridSpacingFact.setMetaData(_metaDataMap[_gridSpacingFactName]); _gridSpacingFact.setMetaData(_metaDataMap[_gridSpacingFactName]);
_turnaroundDistFact.setMetaData(_metaDataMap[_turnaroundDistFactName]); _turnaroundDistFact.setMetaData(_metaDataMap[_turnaroundDistFactName]);
_cameraTriggerDistanceFact.setMetaData(_metaDataMap[_cameraTriggerDistanceFactName]); _cameraTriggerDistanceFact.setMetaData(_metaDataMap[_cameraTriggerDistanceFactName]);
_groundResolutionFact.setMetaData(_metaDataMap[_groundResolutionFactName]);
_frontalOverlapFact.setMetaData(_metaDataMap[_frontalOverlapFactName]);
_sideOverlapFact.setMetaData(_metaDataMap[_sideOverlapFactName]);
_cameraSensorWidthFact.setMetaData(_metaDataMap[_cameraSensorWidthFactName]);
_cameraSensorHeightFact.setMetaData(_metaDataMap[_cameraSensorHeightFactName]);
_cameraResolutionWidthFact.setMetaData(_metaDataMap[_cameraResolutionWidthFactName]);
_cameraResolutionHeightFact.setMetaData(_metaDataMap[_cameraResolutionHeightFactName]);
_cameraFocalLengthFact.setMetaData(_metaDataMap[_cameraFocalLengthFactName]);
connect(&_gridSpacingFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid); connect(&_gridSpacingFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid);
connect(&_gridAngleFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid); connect(&_gridAngleFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid);
@ -74,18 +124,17 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
connect(&_cameraTriggerDistanceFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid); connect(&_cameraTriggerDistanceFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid);
connect(&_gridAltitudeFact, &Fact::valueChanged, this, &SurveyMissionItem::_updateCoordinateAltitude); connect(&_gridAltitudeFact, &Fact::valueChanged, this, &SurveyMissionItem::_updateCoordinateAltitude);
connect(this, &SurveyMissionItem::cameraTriggerChanged, this, &SurveyMissionItem::_cameraTriggerChanged); // Signal to Qml when camera value changes to it can recalc
} connect(&_groundResolutionFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_frontalOverlapFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
const SurveyMissionItem& SurveyMissionItem::operator=(const SurveyMissionItem& other) connect(&_sideOverlapFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
{ connect(&_cameraSensorWidthFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
ComplexMissionItem::operator=(other); connect(&_cameraSensorHeightFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_cameraResolutionWidthFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
_setSurveyDistance(other._surveyDistance); connect(&_cameraResolutionHeightFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
_setCameraShots(other._cameraShots); connect(&_cameraFocalLengthFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
_setCoveredArea(other._coveredArea);
return *this; connect(this, &SurveyMissionItem::cameraTriggerChanged, this, &SurveyMissionItem::_cameraTriggerChanged);
} }
void SurveyMissionItem::_setSurveyDistance(double surveyDistance) void SurveyMissionItem::_setSurveyDistance(double surveyDistance)
@ -190,16 +239,41 @@ void SurveyMissionItem::setDirty(bool dirty)
void SurveyMissionItem::save(QJsonObject& saveObject) const void SurveyMissionItem::save(QJsonObject& saveObject) const
{ {
saveObject[JsonHelper::jsonVersionKey] = 1; saveObject[JsonHelper::jsonVersionKey] = 2;
saveObject[_jsonTypeKey] = _complexType; saveObject[_jsonTypeKey] = _complexType;
saveObject[_jsonIdKey] = sequenceNumber(); saveObject[_jsonIdKey] = sequenceNumber();
saveObject[_jsonGridAltitudeKey] = _gridAltitudeFact.rawValue().toDouble();
saveObject[_jsonGridAltitudeRelativeKey] = _gridAltitudeRelative;
saveObject[_jsonGridAngleKey] = _gridAngleFact.rawValue().toDouble();
saveObject[_jsonGridSpacingKey] = _gridSpacingFact.rawValue().toDouble();
saveObject[_jsonTurnaroundDistKey] = _turnaroundDistFact.rawValue().toDouble();
saveObject[_jsonCameraTriggerKey] = _cameraTrigger; saveObject[_jsonCameraTriggerKey] = _cameraTrigger;
saveObject[_jsonManualGridKey] = _manualGrid;
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitude;
if (_cameraTrigger) {
saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble(); saveObject[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble();
}
QJsonObject gridObject;
gridObject[_jsonGridAltitudeKey] = _gridAltitudeFact.rawValue().toDouble();
gridObject[_jsonGridAltitudeRelativeKey] = _gridAltitudeRelative;
gridObject[_jsonGridAngleKey] = _gridAngleFact.rawValue().toDouble();
gridObject[_jsonGridSpacingKey] = _gridSpacingFact.rawValue().toDouble();
gridObject[_jsonTurnaroundDistKey] = _turnaroundDistFact.rawValue().toDouble();
saveObject[_jsonGridObjectKey] = gridObject;
if (!_manualGrid) {
QJsonObject cameraObject;
cameraObject[_jsonCameraNameKey] = _camera;
cameraObject[_jsonCameraOrientationLandscapeKey] = _cameraOrientationLandscape;
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[_jsonGroundResolutionKey] = _groundResolutionFact.rawValue().toDouble();
cameraObject[_jsonFrontalOverlapKey] = _frontalOverlapFact.rawValue().toInt();
cameraObject[_jsonSideOverlapKey] = _sideOverlapFact.rawValue().toInt();
saveObject[_jsonCameraObjectKey] = cameraObject;
}
// Polygon shape // Polygon shape
@ -213,7 +287,7 @@ void SurveyMissionItem::save(QJsonObject& saveObject) const
polygonArray += jsonValue; polygonArray += jsonValue;
} }
saveObject[_jsonPolygonKey] = polygonArray; saveObject[_jsonPolygonObjectKey] = polygonArray;
} }
void SurveyMissionItem::setSequenceNumber(int sequenceNumber) void SurveyMissionItem::setSequenceNumber(int sequenceNumber)
@ -234,55 +308,115 @@ void SurveyMissionItem::_clear(void)
bool SurveyMissionItem::load(const QJsonObject& complexObject, QString& errorString) bool SurveyMissionItem::load(const QJsonObject& complexObject, QString& errorString)
{ {
_clear(); struct jsonKeyInfo_s {
const char* key;
// Validate requires keys QJsonValue::Type type;
QStringList requiredKeys; bool required;
requiredKeys << JsonHelper::jsonVersionKey << _jsonTypeKey << _jsonIdKey << _jsonPolygonKey << _jsonGridAltitudeKey << _jsonGridAngleKey << _jsonGridSpacingKey << };
_jsonCameraTriggerKey << _jsonCameraTriggerDistanceKey << _jsonGridAltitudeRelativeKey;
if (!JsonHelper::validateRequiredKeys(complexObject, requiredKeys, errorString)) { QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
_clear(); { JsonHelper::jsonVersionKey, QJsonValue::Double, true },
{ _jsonTypeKey, QJsonValue::String, true },
{ _jsonPolygonObjectKey, QJsonValue::Array, true },
{ _jsonIdKey, QJsonValue::Double, true },
{ _jsonGridObjectKey, QJsonValue::Object, true },
{ _jsonCameraObjectKey, QJsonValue::Object, false },
{ _jsonCameraTriggerKey, QJsonValue::Bool, true },
{ _jsonCameraTriggerDistanceKey, QJsonValue::Double, false },
{ _jsonManualGridKey, QJsonValue::Bool, true },
{ _jsonFixedValueIsAltitudeKey, QJsonValue::Bool, true },
};
QList<JsonHelper::KeyValidateInfo> gridKeyInfoList = {
{ _jsonGridAltitudeKey, QJsonValue::Double, true },
{ _jsonGridAltitudeRelativeKey, QJsonValue::Bool, true },
{ _jsonGridAngleKey, QJsonValue::Double, true },
{ _jsonGridSpacingKey, QJsonValue::Double, true },
{ _jsonTurnaroundDistKey, QJsonValue::Double, true },
};
QList<JsonHelper::KeyValidateInfo> cameraKeyInfoList = {
{ _jsonGroundResolutionKey, QJsonValue::Double, true },
{ _jsonFrontalOverlapKey, QJsonValue::Double, true },
{ _jsonSideOverlapKey, QJsonValue::Double, true },
{ _jsonCameraSensorWidthKey, QJsonValue::Double, true },
{ _jsonCameraSensorHeightKey, QJsonValue::Double, true },
{ _jsonCameraResolutionWidthKey, QJsonValue::Double, true },
{ _jsonCameraResolutionHeightKey, QJsonValue::Double, true },
{ _jsonCameraFocalLengthKey, QJsonValue::Double, true },
{ _jsonCameraNameKey, QJsonValue::String, true },
{ _jsonCameraOrientationLandscapeKey, QJsonValue::Bool, true },
};
if (!JsonHelper::validateKeys(complexObject, mainKeyInfoList, errorString)) {
return false; return false;
} }
if (!JsonHelper::validateKeys(complexObject[_jsonGridObjectKey].toObject(), gridKeyInfoList, errorString)) {
// Validate types
QStringList keyList;
QList<QJsonValue::Type> typeList;
keyList << JsonHelper::jsonVersionKey << _jsonTypeKey << _jsonIdKey << _jsonPolygonKey << _jsonGridAltitudeKey << _jsonGridAngleKey << _jsonGridSpacingKey << _jsonTurnaroundDistKey <<
_jsonCameraTriggerKey << _jsonCameraTriggerDistanceKey << _jsonGridAltitudeRelativeKey;
typeList << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::Array << QJsonValue::Double << QJsonValue::Double<< QJsonValue::Double << QJsonValue::Double <<
QJsonValue::Bool << QJsonValue::Double << QJsonValue::Bool;
if (!JsonHelper::validateKeyTypes(complexObject, keyList, typeList, errorString)) {
_clear();
return false; return false;
} }
// Version check // Version check
if (complexObject[JsonHelper::jsonVersionKey].toInt() != 1) { if (complexObject[JsonHelper::jsonVersionKey].toInt() != 2) {
errorString = tr("QGroundControl does not support this version of survey items"); errorString = tr("QGroundControl does not support this version of survey items");
_clear();
return false; return false;
} }
QString complexType = complexObject[_jsonTypeKey].toString(); QString complexType = complexObject[_jsonTypeKey].toString();
if (complexType != _complexType) { if (complexType != _complexType) {
errorString = tr("QGroundControl does not support loading this complex mission item type: %1").arg(complexType); errorString = tr("QGroundControl does not support loading this complex mission item type: %1").arg(complexType);
_clear();
return false; return false;
} }
_clear();
setSequenceNumber(complexObject[_jsonIdKey].toInt()); setSequenceNumber(complexObject[_jsonIdKey].toInt());
_cameraTrigger = complexObject[_jsonCameraTriggerKey].toBool(); _manualGrid = complexObject[_jsonManualGridKey].toBool(true);
_gridAltitudeRelative = complexObject[_jsonGridAltitudeRelativeKey].toBool(); _cameraTrigger = complexObject[_jsonCameraTriggerKey].toBool(false);
_fixedValueIsAltitude = complexObject[_jsonFixedValueIsAltitudeKey].toBool(true);
_gridAltitudeRelative = complexObject[_jsonGridAltitudeRelativeKey].toBool(true);
QJsonObject gridObject = complexObject[_jsonGridObjectKey].toObject();
_gridAltitudeFact.setRawValue (complexObject[_jsonGridAltitudeKey].toDouble()); _gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (complexObject[_jsonGridAngleKey].toDouble()); _gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (complexObject[_jsonGridSpacingKey].toDouble()); _gridSpacingFact.setRawValue (gridObject[_jsonGridSpacingKey].toDouble());
_turnaroundDistFact.setRawValue (complexObject[_jsonTurnaroundDistKey].toDouble()); _turnaroundDistFact.setRawValue (gridObject[_jsonTurnaroundDistKey].toDouble());
if (_cameraTrigger) {
if (!complexObject.contains(_jsonCameraTriggerDistanceKey)) {
errorString = tr("%1 but %2 is missing").arg("cameraTrigger = true").arg("cameraTriggerDistance");
return false;
}
_cameraTriggerDistanceFact.setRawValue(complexObject[_jsonCameraTriggerDistanceKey].toDouble()); _cameraTriggerDistanceFact.setRawValue(complexObject[_jsonCameraTriggerDistanceKey].toDouble());
}
if (!_manualGrid) {
if (!complexObject.contains(_jsonCameraObjectKey)) {
errorString = tr("%1 but %2 object is missing").arg("manualGrid = false").arg("camera");
return false;
}
QJsonObject cameraObject = complexObject[_jsonCameraObjectKey].toObject();
if (!JsonHelper::validateKeys(cameraObject, cameraKeyInfoList, errorString)) {
return false;
}
_camera = cameraObject[_jsonCameraNameKey].toString();
_cameraOrientationLandscape = 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());
}
// Polygon shape // Polygon shape
QJsonArray polygonArray(complexObject[_jsonPolygonKey].toArray()); QJsonArray polygonArray(complexObject[_jsonPolygonObjectKey].toArray());
for (int i=0; i<polygonArray.count(); i++) { for (int i=0; i<polygonArray.count(); i++) {
const QJsonValue& pointValue = polygonArray[i]; const QJsonValue& pointValue = polygonArray[i];
@ -528,6 +662,9 @@ void SurveyMissionItem::_adjustLineDirection(const QList<QLineF>& lineList, QLis
void SurveyMissionItem::_gridGenerator(const QList<QPointF>& polygonPoints, QList<QPointF>& gridPoints) void SurveyMissionItem::_gridGenerator(const QList<QPointF>& polygonPoints, QList<QPointF>& gridPoints)
{ {
double gridAngle = _gridAngleFact.rawValue().toDouble(); double gridAngle = _gridAngleFact.rawValue().toDouble();
double gridSpacing = _gridSpacingFact.rawValue().toDouble();
qCDebug(SurveyMissionItemLog) << "SurveyMissionItem::_gridGenerator gridSpacing:gridAngle" << gridSpacing << gridAngle;
gridPoints.clear(); gridPoints.clear();
@ -557,7 +694,6 @@ void SurveyMissionItem::_gridGenerator(const QList<QPointF>& polygonPoints, QLi
// Create set of rotated parallel lines within the expanded bounding rect. Make the lines larger than the // Create set of rotated parallel lines within the expanded bounding rect. Make the lines larger than the
// bounding box to guarantee intersection. // bounding box to guarantee intersection.
QList<QLineF> lineList; QList<QLineF> lineList;
float gridSpacing = _gridSpacingFact.rawValue().toDouble();
float x = largeBoundRect.topLeft().x() - (gridSpacing / 2); float x = largeBoundRect.topLeft().x() - (gridSpacing / 2);
while (x < largeBoundRect.bottomRight().x()) { while (x < largeBoundRect.bottomRight().x()) {
float yTop = largeBoundRect.topLeft().y() - 100.0; float yTop = largeBoundRect.topLeft().y() - 100.0;
@ -671,3 +807,8 @@ int SurveyMissionItem::cameraShots(void) const
{ {
return _cameraTrigger ? _cameraShots : 0; return _cameraTrigger ? _cameraShots : 0;
} }
void SurveyMissionItem::_cameraValueChanged(void)
{
emit cameraValueChanged();
}

67
src/MissionManager/SurveyMissionItem.h

@ -25,8 +25,6 @@ class SurveyMissionItem : public ComplexMissionItem
public: public:
SurveyMissionItem(Vehicle* vehicle, QObject* parent = NULL); SurveyMissionItem(Vehicle* vehicle, QObject* parent = NULL);
const SurveyMissionItem& operator=(const SurveyMissionItem& other);
Q_PROPERTY(Fact* gridAltitude READ gridAltitude CONSTANT) Q_PROPERTY(Fact* gridAltitude READ gridAltitude CONSTANT)
Q_PROPERTY(bool gridAltitudeRelative MEMBER _gridAltitudeRelative NOTIFY gridAltitudeRelativeChanged) Q_PROPERTY(bool gridAltitudeRelative MEMBER _gridAltitudeRelative NOTIFY gridAltitudeRelativeChanged)
Q_PROPERTY(Fact* gridAngle READ gridAngle CONSTANT) Q_PROPERTY(Fact* gridAngle READ gridAngle CONSTANT)
@ -34,10 +32,22 @@ public:
Q_PROPERTY(Fact* turnaroundDist READ turnaroundDist CONSTANT) Q_PROPERTY(Fact* turnaroundDist READ turnaroundDist CONSTANT)
Q_PROPERTY(bool cameraTrigger MEMBER _cameraTrigger NOTIFY cameraTriggerChanged) Q_PROPERTY(bool cameraTrigger MEMBER _cameraTrigger NOTIFY cameraTriggerChanged)
Q_PROPERTY(Fact* cameraTriggerDistance READ cameraTriggerDistance CONSTANT) Q_PROPERTY(Fact* cameraTriggerDistance READ cameraTriggerDistance CONSTANT)
Q_PROPERTY(Fact* groundResolution READ groundResolution CONSTANT)
Q_PROPERTY(Fact* frontalOverlap READ frontalOverlap CONSTANT)
Q_PROPERTY(Fact* sideOverlap READ sideOverlap CONSTANT)
Q_PROPERTY(Fact* cameraSensorWidth READ cameraSensorWidth CONSTANT)
Q_PROPERTY(Fact* cameraSensorHeight READ cameraSensorHeight CONSTANT)
Q_PROPERTY(Fact* cameraResolutionWidth READ cameraResolutionWidth CONSTANT)
Q_PROPERTY(Fact* cameraResolutionHeight READ cameraResolutionHeight CONSTANT)
Q_PROPERTY(Fact* cameraFocalLength READ cameraFocalLength CONSTANT)
Q_PROPERTY(QVariantList polygonPath READ polygonPath NOTIFY polygonPathChanged) Q_PROPERTY(QVariantList polygonPath READ polygonPath NOTIFY polygonPathChanged)
Q_PROPERTY(QVariantList gridPoints READ gridPoints NOTIFY gridPointsChanged) Q_PROPERTY(QVariantList gridPoints READ gridPoints NOTIFY gridPointsChanged)
Q_PROPERTY(int cameraShots READ cameraShots NOTIFY cameraShotsChanged) Q_PROPERTY(int cameraShots READ cameraShots NOTIFY cameraShotsChanged)
Q_PROPERTY(double coveredArea READ coveredArea NOTIFY coveredAreaChanged) Q_PROPERTY(double coveredArea READ coveredArea NOTIFY coveredAreaChanged)
Q_PROPERTY(bool fixedValueIsAltitude MEMBER _fixedValueIsAltitude NOTIFY fixedValueIsAltitudeChanged)
Q_PROPERTY(bool cameraOrientationLandscape MEMBER _cameraOrientationLandscape NOTIFY cameraOrientationLandscapeChanged)
Q_PROPERTY(bool manualGrid MEMBER _manualGrid NOTIFY manualGridChanged)
Q_PROPERTY(QString camera MEMBER _camera NOTIFY cameraChanged)
Q_INVOKABLE void clearPolygon(void); Q_INVOKABLE void clearPolygon(void);
Q_INVOKABLE void addPolygonCoordinate(const QGeoCoordinate coordinate); Q_INVOKABLE void addPolygonCoordinate(const QGeoCoordinate coordinate);
@ -51,6 +61,14 @@ public:
Fact* gridSpacing (void) { return &_gridSpacingFact; } Fact* gridSpacing (void) { return &_gridSpacingFact; }
Fact* turnaroundDist (void) { return &_turnaroundDistFact; } Fact* turnaroundDist (void) { return &_turnaroundDistFact; }
Fact* cameraTriggerDistance (void) { return &_cameraTriggerDistanceFact; } Fact* cameraTriggerDistance (void) { return &_cameraTriggerDistanceFact; }
Fact* groundResolution (void) { return &_groundResolutionFact; }
Fact* frontalOverlap (void) { return &_frontalOverlapFact; }
Fact* sideOverlap (void) { return &_sideOverlapFact; }
Fact* cameraSensorWidth (void) { return &_cameraSensorWidthFact; }
Fact* cameraSensorHeight (void) { return &_cameraSensorHeightFact; }
Fact* cameraResolutionWidth (void) { return &_cameraResolutionWidthFact; }
Fact* cameraResolutionHeight (void) { return &_cameraResolutionHeightFact; }
Fact* cameraFocalLength (void) { return &_cameraFocalLengthFact; }
int cameraShots(void) const; int cameraShots(void) const;
double coveredArea(void) const { return _coveredArea; } double coveredArea(void) const { return _coveredArea; }
@ -95,6 +113,12 @@ signals:
void gridAltitudeRelativeChanged (bool gridAltitudeRelative); void gridAltitudeRelativeChanged (bool gridAltitudeRelative);
void cameraShotsChanged (int cameraShots); void cameraShotsChanged (int cameraShots);
void coveredAreaChanged (double coveredArea); void coveredAreaChanged (double coveredArea);
void cameraValueChanged (void);
void fixedValueIsAltitudeChanged (bool fixedValueIsAltitude);
void gridTypeChanged (QString gridType);
void cameraOrientationLandscapeChanged (bool cameraOrientationLandscape);
void cameraChanged (QString camera);
void manualGridChanged (bool manualGrid);
private slots: private slots:
void _cameraTriggerChanged(void); void _cameraTriggerChanged(void);
@ -113,6 +137,7 @@ private:
void _setSurveyDistance(double surveyDistance); void _setSurveyDistance(double surveyDistance);
void _setCameraShots(int cameraShots); void _setCameraShots(int cameraShots);
void _setCoveredArea(double coveredArea); void _setCoveredArea(double coveredArea);
void _cameraValueChanged(void);
int _sequenceNumber; int _sequenceNumber;
bool _dirty; bool _dirty;
@ -121,9 +146,12 @@ private:
QGeoCoordinate _coordinate; QGeoCoordinate _coordinate;
QGeoCoordinate _exitCoordinate; QGeoCoordinate _exitCoordinate;
double _altitude; double _altitude;
double _gridAngle;
bool _cameraTrigger; bool _cameraTrigger;
bool _gridAltitudeRelative; bool _gridAltitudeRelative;
bool _manualGrid;
QString _camera;
bool _cameraOrientationLandscape;
bool _fixedValueIsAltitude;
double _surveyDistance; double _surveyDistance;
int _cameraShots; int _cameraShots;
@ -134,12 +162,21 @@ private:
Fact _gridSpacingFact; Fact _gridSpacingFact;
Fact _turnaroundDistFact; Fact _turnaroundDistFact;
Fact _cameraTriggerDistanceFact; Fact _cameraTriggerDistanceFact;
Fact _groundResolutionFact;
Fact _frontalOverlapFact;
Fact _sideOverlapFact;
Fact _cameraSensorWidthFact;
Fact _cameraSensorHeightFact;
Fact _cameraResolutionWidthFact;
Fact _cameraResolutionHeightFact;
Fact _cameraFocalLengthFact;
static QMap<QString, FactMetaData*> _metaDataMap; static QMap<QString, FactMetaData*> _metaDataMap;
static const char* _jsonTypeKey; static const char* _jsonTypeKey;
static const char* _jsonPolygonKey; static const char* _jsonPolygonObjectKey;
static const char* _jsonIdKey; static const char* _jsonIdKey;
static const char* _jsonGridObjectKey;
static const char* _jsonGridAltitudeKey; static const char* _jsonGridAltitudeKey;
static const char* _jsonGridAltitudeRelativeKey; static const char* _jsonGridAltitudeRelativeKey;
static const char* _jsonGridAngleKey; static const char* _jsonGridAngleKey;
@ -147,12 +184,34 @@ private:
static const char* _jsonTurnaroundDistKey; static const char* _jsonTurnaroundDistKey;
static const char* _jsonCameraTriggerKey; static const char* _jsonCameraTriggerKey;
static const char* _jsonCameraTriggerDistanceKey; static const char* _jsonCameraTriggerDistanceKey;
static const char* _jsonGroundResolutionKey;
static const char* _jsonFrontalOverlapKey;
static const char* _jsonSideOverlapKey;
static const char* _jsonCameraSensorWidthKey;
static const char* _jsonCameraSensorHeightKey;
static const char* _jsonCameraResolutionWidthKey;
static const char* _jsonCameraResolutionHeightKey;
static const char* _jsonCameraFocalLengthKey;
static const char* _jsonManualGridKey;
static const char* _jsonCameraObjectKey;
static const char* _jsonCameraNameKey;
static const char* _jsonCameraOrientationLandscapeKey;
static const char* _jsonFixedValueIsAltitudeKey;
static const char* _gridAltitudeFactName; static const char* _gridAltitudeFactName;
static const char* _gridAngleFactName; static const char* _gridAngleFactName;
static const char* _gridSpacingFactName; static const char* _gridSpacingFactName;
static const char* _turnaroundDistFactName; static const char* _turnaroundDistFactName;
static const char* _cameraTriggerDistanceFactName; static const char* _cameraTriggerDistanceFactName;
static const char* _groundResolutionFactName;
static const char* _frontalOverlapFactName;
static const char* _sideOverlapFactName;
static const char* _cameraSensorWidthFactName;
static const char* _cameraSensorHeightFactName;
static const char* _cameraResolutionWidthFactName;
static const char* _cameraResolutionHeightFactName;
static const char* _cameraFocalLengthFactName;
static const char* _complexType; static const char* _complexType;
}; };

Loading…
Cancel
Save