Browse Source

Major rework of Survey ui

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

756
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
@ -21,127 +22,165 @@ Rectangle {
//property real availableWidth ///< Width for control //property real availableWidth ///< Width for control
//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
ListElement {
text: qsTr("Custom") Component.onCompleted: {
sensorWidth: 0 cameraModelList.setProperty(_gridTypeCustomCamera, "sensorWidth", missionItem.cameraSensorWidth.rawValue)
sensorHeight: 0 cameraModelList.setProperty(_gridTypeCustomCamera, "sensorHeight", missionItem.cameraSensorHeight.rawValue)
imageWidth: 0 cameraModelList.setProperty(_gridTypeCustomCamera, "imageWidth", missionItem.cameraResolutionWidth.rawValue)
imageHeight: 0 cameraModelList.setProperty(_gridTypeCustomCamera, "imageHeight", missionItem.cameraResolutionHeight.rawValue)
focalLength: 0 cameraModelList.setProperty(_gridTypeCustomCamera, "focalLength", missionItem.cameraFocalLength.rawValue)
} }
ListElement {
text: qsTr("Sony ILCE-QX1") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications ListElement {
sensorWidth: 23.2 //http://www.sony.com/electronics/camera-lenses/sel16f28/specifications text: qsTr("Manual Grid (no camera specs)")
sensorHeight: 15.4 }
imageWidth: 5456 ListElement {
imageHeight: 3632 text: qsTr("Custom Camera Grid")
focalLength: 16 }
} ListElement {
ListElement { text: qsTr("Sony ILCE-QX1") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications
text: qsTr("Canon S100 PowerShot") sensorWidth: 23.2 //http://www.sony.com/electronics/camera-lenses/sel16f28/specifications
sensorWidth: 7.6 sensorHeight: 15.4
sensorHeight: 5.7 imageWidth: 5456
imageWidth: 4000 imageHeight: 3632
imageHeight: 3000 focalLength: 16
focalLength: 5.2 }
} ListElement {
ListElement { text: qsTr("Canon S100 PowerShot")
text: qsTr("Canon SX260 HS PowerShot") sensorWidth: 7.6
sensorWidth: 6.17 sensorHeight: 5.7
sensorHeight: 4.55 imageWidth: 4000
imageWidth: 4000 imageHeight: 3000
imageHeight: 3000 focalLength: 5.2
focalLength: 4.5 }
} ListElement {
ListElement { text: qsTr("Canon SX260 HS PowerShot")
text: qsTr("Canon EOS-M 22mm") sensorWidth: 6.17
sensorWidth: 22.3 sensorHeight: 4.55
sensorHeight: 14.9 imageWidth: 4000
imageWidth: 5184 imageHeight: 3000
imageHeight: 3456 focalLength: 4.5
focalLength: 22 }
} ListElement {
ListElement { text: qsTr("Canon EOS-M 22mm")
text: qsTr("Sony a6000 16mm") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-6000-body-kit#product_details_default sensorWidth: 22.3
sensorWidth: 23.5 sensorHeight: 14.9
sensorHeight: 15.6 imageWidth: 5184
imageWidth: 6000 imageHeight: 3456
imageHeight: 4000 focalLength: 22
focalLength: 16 }
} ListElement {
} text: qsTr("Sony a6000 16mm") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-6000-body-kit#product_details_default
sensorWidth: 23.5
sensorHeight: 15.6
imageWidth: 6000
imageHeight: 4000
focalLength: 16
}
}
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 )
missionItem.gridAltitude.rawValue = altitude if (missionItem.fixedValueIsAltitude) {
missionItem.groundResolution.rawValue = groundResolution
} else {
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,13 +193,14 @@ 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()
} }
function polygonCaptureFinished(coordinates) { function polygonCaptureFinished(coordinates) {
@ -176,15 +216,42 @@ 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: {
recalcFromMissionValues() onCurrentChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
recalcFromCameraValues()
}
} }
} }
ExclusiveGroup { id: fixedValueGroup }
Column { Column {
id: editorColumn id: editorColumn
anchors.margins: _margin anchors.margins: _margin
@ -198,307 +265,292 @@ 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 { QGCComboBox {
anchors.baseline: textField.baseline id: gridTypeCombo
anchors.left: parent.left anchors.left: parent.left
text: modelData.name + ":" anchors.right: parent.right
model: cameraModelList
currentIndex: -1
Component.onCompleted: {
if (missionItem.manualGrid) {
gridTypeCombo.currentIndex = _gridTypeManual
} else {
var index = gridTypeCombo.find(missionItem.camera)
if (index == -1) {
console.log("Couldn't find camera", missionItem.camera)
gridTypeCombo.currentIndex = _gridTypeManual
} else {
gridTypeCombo.currentIndex = index
}
} }
}
FactTextField { onActivated: {
id: textField if (index == _gridTypeManual) {
anchors.right: parent.right missionItem.manualGrid = true
width: _editFieldWidth } else {
showUnits: true missionItem.manualGrid = false
fact: modelData missionItem.camera = gridTypeCombo.textAt(index)
onEditingFinished: recalcFromMissionValues() _noCameraValueRecalc = true
validator: DoubleValidator{bottom:0.0; decimals:2} 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()
} }
} }
} }
QGCCheckBox { // Camera based grid ui
Column {
anchors.left: parent.left anchors.left: parent.left
text: qsTr("Relative altitude") anchors.right: parent.right
checked: missionItem.gridAltitudeRelative spacing: _margin
onClicked: missionItem.gridAltitudeRelative = checked visible: gridTypeCombo.currentIndex != _gridTypeManual
}
Grid { Row {
columns: 2 spacing: _margin
columnSpacing: ScreenTools.defaultFontPixelWidth
rowSpacing: _margin
verticalItemAlignment: Grid.AlignVCenter
QGCLabel { QGCRadioButton {
text: qsTr("GSD:") id: cameraOrientationLandscape
width: _editFieldWidth width: _editFieldWidth
} text: "Landscape"
QGCTextField { checked: true
id: gsdField exclusiveGroup: cameraOrientationGroup
width: _editFieldWidth }
unitsLabel: "cm/px"
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: DoubleValidator{bottom:0.0; decimals:2}
}
QGCLabel { text: qsTr("Frontal Overlap:") } QGCRadioButton {
QGCTextField { id: cameraOrientationPortrait
id: frontalOverlapField text: "Portrait"
width: _editFieldWidth exclusiveGroup: cameraOrientationGroup
unitsLabel: "%" }
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: IntValidator {bottom:0}
} }
QGCLabel { text: qsTr("Side Overlap:") } Column {
QGCTextField { anchors.left: parent.left
id: sideOverlapField anchors.right: parent.right
width: _editFieldWidth spacing: _margin
unitsLabel: "%" visible: gridTypeCombo.currentIndex == _gridTypeCustomCamera
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: IntValidator {bottom:0}
}
Component.onCompleted: recalcFromMissionValues() GridLayout {
} columns: 3
columnSpacing: _margin
rowSpacing: _margin
QGCLabel { text: qsTr("Camera:") } property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10
Rectangle { QGCLabel { }
anchors.left: parent.left QGCLabel { text: qsTr("Width") }
anchors.right: parent.right QGCLabel { text: qsTr("Height") }
height: 1
color: qgcPal.text
}
Grid { QGCLabel { text: qsTr("Sensor:") }
columns: 2 FactTextField {
spacing: ScreenTools.defaultFontPixelWidth Layout.preferredWidth: parent._fieldWidth
verticalItemAlignment: Grid.AlignVCenter fact: missionItem.cameraSensorWidth
}
QGCRadioButton { FactTextField {
id: cameraOrientationLandscape Layout.preferredWidth: parent._fieldWidth
width: _editFieldWidth fact: missionItem.cameraSensorHeight
text: "Landscape" }
checked: true
exclusiveGroup: cameraOrientationGroup QGCLabel { text: qsTr("Image:") }
FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraResolutionWidth
}
FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraResolutionHeight
}
}
FactTextFieldRow {
spacing: _margin
fact: missionItem.cameraFocalLength
}
} // Column - custom camera
QGCLabel { text: qsTr("Image Overlap") }
Row {
spacing: _margin
Item {
width: ScreenTools.defaultFontPixelWidth * 2
height: 1
}
QGCLabel {
anchors.baseline: frontalOverlapField.baseline
text: qsTr("Frontal:")
}
FactTextField {
id: frontalOverlapField
width: ScreenTools.defaultFontPixelWidth * 7
fact: missionItem.frontalOverlap
}
QGCLabel {
anchors.baseline: frontalOverlapField.baseline
text: qsTr("Side:")
}
FactTextField {
width: frontalOverlapField.width
fact: missionItem.sideOverlap
}
} }
QGCRadioButton { QGCLabel { text: qsTr("Grid:") }
id: cameraOrientationPortrait
text: "Portrait" Rectangle {
exclusiveGroup: cameraOrientationGroup anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
} }
QGCCheckBox { FactTextFieldGrid {
id: cameraTrigger anchors.left: parent.left
width: _editFieldWidth anchors.right: parent.right
text: qsTr("Trigger:") columnSpacing: _margin
checked: missionItem.cameraTrigger rowSpacing: _margin
onClicked: missionItem.cameraTrigger = checked factList: [ missionItem.gridAngle, missionItem.turnaroundDist ]
} }
FactTextField { QGCLabel {
width: _editFieldWidth anchors.left: parent.left
showUnits: true anchors.right: parent.right
fact: missionItem.cameraTriggerDistance wrapMode: Text.WordWrap
enabled: missionItem.cameraTrigger font.pointSize: ScreenTools.smallFontPointSize
onEditingFinished: recalcFromMissionValues() text: qsTr("Which value would you like to keep constant as you adjust other settings:")
validator: DoubleValidator{bottom:0.0; decimals:2}
} }
}
Component { RowLayout {
id: cameraFields anchors.left: parent.left
anchors.right: parent.right
QGCViewDialog { spacing: _margin
Column { QGCRadioButton {
id: dialogColumn id: fixedAltitudeRadio
anchors.margins: _margin anchors.baseline: gridAltitudeField.baseline
anchors.top: parent.top text: qsTr("Altitude:")
anchors.left: parent.left checked: missionItem.fixedValueIsAltitude
anchors.right: parent.right exclusiveGroup: fixedValueGroup
spacing: _margin * 5 onClicked: missionItem.fixedValueIsAltitude = true
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
id: selectCameraModelText
text: qsTr("Select Camera Model:")
}
QGCComboBox {
id: cameraModelCombo
model: cameraModelList
width: dialogColumn.width - selectCameraModelText.width - ScreenTools.defaultFontPixelWidth
onActivated: {
cameraIndex = index
}
Component.onCompleted: {
var index = cameraIndex
if (index === -1) {
console.warn("Active camera model name not in combo", cameraIndex)
} else {
cameraModelCombo.currentIndex = index
}
}
}
}
Grid { FactTextField {
columns: 2 id: gridAltitudeField
spacing: ScreenTools.defaultFontPixelWidth Layout.fillWidth: true
verticalItemAlignment: Grid.AlignVCenter fact: missionItem.gridAltitude
enabled: fixedAltitudeRadio.checked
QGCLabel { text: qsTr("Sensor Width:") }
QGCTextField {
id: sensorWidthField
unitsLabel: "mm"
showUnits: true
text: cameraModelList.get(cameraIndex).sensorWidth.toFixed(2)
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:") }
QGCTextField {
id: sensorHeightField
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))
}
}
}
QGCLabel { text: qsTr("Image Width:") }
QGCTextField {
id: imageWidthField
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("Image Height:") }
QGCTextField {
id: imageHeightField
unitsLabel: "px"
showUnits: true
text: cameraModelList.get(cameraIndex).imageHeight.toFixed(0)
readOnly: cameraIndex != 0
enabled: cameraIndex == 0
validator: IntValidator {bottom:0}
onEditingFinished: {
if (cameraIndex == 0) {
cameraModelList.setProperty(cameraIndex, "imageHeight", Number(text))
}
}
}
QGCLabel { text: qsTr("Focal Length:") }
QGCTextField {
id: focalLengthField
unitsLabel: "mm"
showUnits: true
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))
}
}
}
}
} }
}
function accept() { RowLayout {
hideDialog() anchors.left: parent.left
recalcFromCameraValues() 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
} }
}//QGCViewDialog
}//Component
FactTextField {
id: groundResolutionField
Layout.fillWidth: true
fact: missionItem.groundResolution
enabled: fixedGroundResolutionRadio.checked
}
}
}
// 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
factList: [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
}
QGCLabel { QGCCheckBox {
text: qsTr("Sensor Size:") anchors.left: parent.left
width: _editFieldWidth text: qsTr("Relative altitude")
} checked: missionItem.gridAltitudeRelative
QGCLabel { onClicked: missionItem.gridAltitudeRelative = checked
text: cameraModelList.get(cameraIndex).sensorWidth.toFixed(2) + qsTr(" x ") + cameraModelList.get(cameraIndex).sensorHeight.toFixed(2) }
width: _editFieldWidth
}
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
QGCCheckBox {
id: cameraTrigger
anchors.baseline: cameraTriggerDistanceField.baseline
text: qsTr("Trigger Distance:")
checked: missionItem.cameraTrigger
onClicked: missionItem.cameraTrigger = checked
}
onClicked: { FactTextField {
qgcView.showDialog(cameraFields, qsTr("Set Camera Model"), qgcView.showDialogDefaultWidth, StandardButton.Save) id: cameraTriggerDistanceField
Layout.fillWidth: true
fact: missionItem.cameraTriggerDistance
enabled: missionItem.cameraTrigger
}
} }
} }
QGCLabel { text: qsTr("Polygon:") } QGCLabel { text: qsTr("Polygon:") }
Rectangle { Rectangle {

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"
} }
] ]

285
src/MissionManager/SurveyMissionItem.cc

@ -17,22 +17,44 @@
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::_jsonCameraTriggerKey = "cameraTrigger"; const char* SurveyMissionItem::_jsonTurnaroundDistKey = "turnAroundDistance";
const char* SurveyMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance"; const char* SurveyMissionItem::_jsonCameraTriggerKey = "cameraTrigger";
const char* SurveyMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance";
const char* SurveyMissionItem::_gridAltitudeFactName = "Altitude"; const char* SurveyMissionItem::_jsonGroundResolutionKey = "groundResolution";
const char* SurveyMissionItem::_gridAngleFactName = "Grid angle"; const char* SurveyMissionItem::_jsonFrontalOverlapKey = "imageFrontalOverlap";
const char* SurveyMissionItem::_gridSpacingFactName = "Grid spacing"; const char* SurveyMissionItem::_jsonSideOverlapKey = "imageSizeOverlap";
const char* SurveyMissionItem::_turnaroundDistFactName = "Turnaround dist."; const char* SurveyMissionItem::_jsonCameraSensorWidthKey = "sensorWidth";
const char* SurveyMissionItem::_cameraTriggerDistanceFactName = "Camera trigger distance"; 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::_gridAngleFactName = "Grid angle";
const char* SurveyMissionItem::_gridSpacingFactName = "Grid spacing";
const char* SurveyMissionItem::_turnaroundDistFactName = "Turnaround dist";
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,29 +66,57 @@ 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)
, _gridAltitudeFact (0, _gridAltitudeFactName, FactMetaData::valueTypeDouble) , _gridAltitudeFact (0, _gridAltitudeFactName, FactMetaData::valueTypeDouble)
, _gridAngleFact (0, _gridAngleFactName, FactMetaData::valueTypeDouble) , _gridAngleFact (0, _gridAngleFactName, FactMetaData::valueTypeDouble)
, _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[_jsonCameraTriggerDistanceKey] = _cameraTriggerDistanceFact.rawValue().toDouble(); saveObject[_jsonManualGridKey] = _manualGrid;
saveObject[_jsonFixedValueIsAltitudeKey] = _fixedValueIsAltitude;
if (_cameraTrigger) {
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);
_gridAltitudeFact.setRawValue (complexObject[_jsonGridAltitudeKey].toDouble()); QJsonObject gridObject = complexObject[_jsonGridObjectKey].toObject();
_gridAngleFact.setRawValue (complexObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (complexObject[_jsonGridSpacingKey].toDouble()); _gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_turnaroundDistFact.setRawValue (complexObject[_jsonTurnaroundDistKey].toDouble()); _gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].toDouble());
_cameraTriggerDistanceFact.setRawValue (complexObject[_jsonCameraTriggerDistanceKey].toDouble()); _gridSpacingFact.setRawValue (gridObject[_jsonGridSpacingKey].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());
}
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();
}

143
src/MissionManager/SurveyMissionItem.h

@ -25,19 +25,29 @@ 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(bool gridAltitudeRelative MEMBER _gridAltitudeRelative NOTIFY gridAltitudeRelativeChanged)
Q_PROPERTY(Fact* gridAltitude READ gridAltitude CONSTANT) Q_PROPERTY(Fact* gridAngle READ gridAngle CONSTANT)
Q_PROPERTY(bool gridAltitudeRelative MEMBER _gridAltitudeRelative NOTIFY gridAltitudeRelativeChanged) Q_PROPERTY(Fact* gridSpacing READ gridSpacing CONSTANT)
Q_PROPERTY(Fact* gridAngle READ gridAngle CONSTANT) Q_PROPERTY(Fact* turnaroundDist READ turnaroundDist CONSTANT)
Q_PROPERTY(Fact* gridSpacing READ gridSpacing CONSTANT) Q_PROPERTY(bool cameraTrigger MEMBER _cameraTrigger NOTIFY cameraTriggerChanged)
Q_PROPERTY(Fact* turnaroundDist READ turnaroundDist CONSTANT) Q_PROPERTY(Fact* cameraTriggerDistance READ cameraTriggerDistance CONSTANT)
Q_PROPERTY(bool cameraTrigger MEMBER _cameraTrigger NOTIFY cameraTriggerChanged) Q_PROPERTY(Fact* groundResolution READ groundResolution CONSTANT)
Q_PROPERTY(Fact* cameraTriggerDistance READ cameraTriggerDistance CONSTANT) Q_PROPERTY(Fact* frontalOverlap READ frontalOverlap CONSTANT)
Q_PROPERTY(QVariantList polygonPath READ polygonPath NOTIFY polygonPathChanged) Q_PROPERTY(Fact* sideOverlap READ sideOverlap CONSTANT)
Q_PROPERTY(QVariantList gridPoints READ gridPoints NOTIFY gridPointsChanged) Q_PROPERTY(Fact* cameraSensorWidth READ cameraSensorWidth CONSTANT)
Q_PROPERTY(int cameraShots READ cameraShots NOTIFY cameraShotsChanged) Q_PROPERTY(Fact* cameraSensorHeight READ cameraSensorHeight CONSTANT)
Q_PROPERTY(double coveredArea READ coveredArea NOTIFY coveredAreaChanged) 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 gridPoints READ gridPoints NOTIFY gridPointsChanged)
Q_PROPERTY(int cameraShots READ cameraShots NOTIFY cameraShotsChanged)
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);
@ -46,11 +56,19 @@ public:
QVariantList polygonPath(void) { return _polygonPath; } QVariantList polygonPath(void) { return _polygonPath; }
QVariantList gridPoints (void) { return _gridPoints; } QVariantList gridPoints (void) { return _gridPoints; }
Fact* gridAltitude(void) { return &_gridAltitudeFact; } Fact* gridAltitude (void) { return &_gridAltitudeFact; }
Fact* gridAngle(void) { return &_gridAngleFact; } Fact* gridAngle (void) { return &_gridAngleFact; }
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; }
@ -87,14 +105,20 @@ public:
void save (QJsonObject& saveObject) const final; void save (QJsonObject& saveObject) const final;
signals: signals:
void polygonPathChanged (void); void polygonPathChanged (void);
void altitudeChanged (double altitude); void altitudeChanged (double altitude);
void gridAngleChanged (double gridAngle); void gridAngleChanged (double gridAngle);
void gridPointsChanged (void); void gridPointsChanged (void);
void cameraTriggerChanged (bool cameraTrigger); void cameraTriggerChanged (bool cameraTrigger);
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,33 +137,46 @@ 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;
bool _dirty; int _sequenceNumber;
QVariantList _polygonPath; bool _dirty;
QVariantList _gridPoints; QVariantList _polygonPath;
QGeoCoordinate _coordinate; QVariantList _gridPoints;
QGeoCoordinate _exitCoordinate; QGeoCoordinate _coordinate;
double _altitude; QGeoCoordinate _exitCoordinate;
double _gridAngle; double _altitude;
bool _cameraTrigger; bool _cameraTrigger;
bool _gridAltitudeRelative; bool _gridAltitudeRelative;
bool _manualGrid;
double _surveyDistance; QString _camera;
int _cameraShots; bool _cameraOrientationLandscape;
double _coveredArea; bool _fixedValueIsAltitude;
double _surveyDistance;
int _cameraShots;
double _coveredArea;
Fact _gridAltitudeFact; Fact _gridAltitudeFact;
Fact _gridAngleFact; Fact _gridAngleFact;
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