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 @@ @@ -1,6 +1,7 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
@ -21,127 +22,165 @@ Rectangle { @@ -21,127 +22,165 @@ Rectangle {
//property real availableWidth ///< Width for control
//property var missionItem ///< Mission Item for editor
property real _margin: ScreenTools.defaultFontPixelWidth / 2
property int cameraIndex: 1
property real _margin: ScreenTools.defaultFontPixelWidth / 2
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 {
id: cameraModelList
ListElement {
text: qsTr("Custom")
sensorWidth: 0
sensorHeight: 0
imageWidth: 0
imageHeight: 0
focalLength: 0
}
ListElement {
text: qsTr("Sony ILCE-QX1") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications
sensorWidth: 23.2 //http://www.sony.com/electronics/camera-lenses/sel16f28/specifications
sensorHeight: 15.4
imageWidth: 5456
imageHeight: 3632
focalLength: 16
}
ListElement {
text: qsTr("Canon S100 PowerShot")
sensorWidth: 7.6
sensorHeight: 5.7
imageWidth: 4000
imageHeight: 3000
focalLength: 5.2
}
ListElement {
text: qsTr("Canon SX260 HS PowerShot")
sensorWidth: 6.17
sensorHeight: 4.55
imageWidth: 4000
imageHeight: 3000
focalLength: 4.5
}
ListElement {
text: qsTr("Canon EOS-M 22mm")
sensorWidth: 22.3
sensorHeight: 14.9
imageWidth: 5184
imageHeight: 3456
focalLength: 22
}
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
}
}
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 {
text: qsTr("Manual Grid (no camera specs)")
}
ListElement {
text: qsTr("Custom Camera Grid")
}
ListElement {
text: qsTr("Sony ILCE-QX1") //http://www.sony.co.uk/electronics/interchangeable-lens-cameras/ilce-qx1-body-kit/specifications
sensorWidth: 23.2 //http://www.sony.com/electronics/camera-lenses/sel16f28/specifications
sensorHeight: 15.4
imageWidth: 5456
imageHeight: 3632
focalLength: 16
}
ListElement {
text: qsTr("Canon S100 PowerShot")
sensorWidth: 7.6
sensorHeight: 5.7
imageWidth: 4000
imageHeight: 3000
focalLength: 5.2
}
ListElement {
text: qsTr("Canon SX260 HS PowerShot")
sensorWidth: 6.17
sensorHeight: 4.55
imageWidth: 4000
imageHeight: 3000
focalLength: 4.5
}
ListElement {
text: qsTr("Canon EOS-M 22mm")
sensorWidth: 22.3
sensorHeight: 14.9
imageWidth: 5184
imageHeight: 3456
focalLength: 22
}
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() {
var focalLength = cameraModelList.get(cameraIndex).focalLength
var sensorWidth = cameraModelList.get(cameraIndex).sensorWidth
var sensorHeight = cameraModelList.get(cameraIndex).sensorHeight
var imageWidth = cameraModelList.get(cameraIndex).imageWidth
var imageHeight = cameraModelList.get(cameraIndex).imageHeight
var gsd = Number(gsdField.text)
var frontalOverlap = Number(frontalOverlapField.text)
var sideOverlap = Number(sideOverlapField.text)
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
missionItem.gridSpacing.rawValue = 0
missionItem.cameraTriggerDistance.rawValue = 0
var focalLength = missionItem.cameraFocalLength.rawValue
var sensorWidth = missionItem.cameraSensorWidth.rawValue
var sensorHeight = missionItem.cameraSensorHeight.rawValue
var imageWidth = missionItem.cameraResolutionWidth.rawValue
var imageHeight = missionItem.cameraResolutionHeight.rawValue
var altitude = missionItem.gridAltitude.rawValue
var groundResolution = missionItem.groundResolution.rawValue
var frontalOverlap = missionItem.frontalOverlap.rawValue
var sideOverlap = missionItem.sideOverlap.rawValue
if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || groundResolution <= 0) {
return
}
var altitude
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 imageSizeSideGround //size in side (non flying) direction of the image on the ground
var imageSizeFrontGround //size in front (flying) direction of the image on the ground
var gridSpacing
var cameraTriggerDistance
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) {
imageSizeSideGround = (imageWidth * gsd) / 100
imageSizeFrontGround = (imageHeight * gsd) / 100
imageSizeSideGround = (imageWidth * groundResolution) / 100
imageSizeFrontGround = (imageHeight * groundResolution) / 100
} else {
imageSizeSideGround = (imageHeight * gsd) / 100
imageSizeFrontGround = (imageWidth * gsd) / 100
imageSizeSideGround = (imageHeight * groundResolution) / 100
imageSizeFrontGround = (imageWidth * groundResolution) / 100
}
gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 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.cameraTriggerDistance.rawValue = cameraTriggerDistance
}
/*
function recalcFromMissionValues() {
var focalLength = cameraModelList.get(cameraIndex).focalLength
var sensorWidth = cameraModelList.get(cameraIndex).sensorWidth
var sensorHeight = cameraModelList.get(cameraIndex).sensorHeight
var imageWidth = cameraModelList.get(cameraIndex).imageWidth
var imageHeight = cameraModelList.get(cameraIndex).imageHeight
var focalLength = missionItem.cameraFocalLength.rawValue
var sensorWidth = missionItem.cameraSensorWidth.rawValue
var sensorHeight = missionItem.cameraSensorHeight.rawValue
var imageWidth = missionItem.cameraResolutionWidth.rawValue
var imageHeight = missionItem.cameraResolutionHeight.rawValue
var altitude = missionItem.gridAltitude.rawValue
var gridSpacing = missionItem.gridSpacing.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) {
gsdField.text = "0.0"
sideOverlapField.text = "0"
frontalOverlapField.text = "0"
missionItem.groundResolution.rawValue = 0
missionItem.sideOverlap = 0
missionItem.frontalOverlap = 0
return
}
var gsd
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 groundResolution
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
gsd = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
if (cameraOrientationLandscape.checked) {
imageSizeSideGround = (imageWidth * gsd) / 100
@ -154,13 +193,14 @@ Rectangle { @@ -154,13 +193,14 @@ Rectangle {
var sideOverlap = (imageSizeSideGround == 0 ? 0 : 100 - (gridSpacing*100 / imageSizeSideGround))
var frontOverlap = (imageSizeFrontGround == 0 ? 0 : 100 - (cameraTriggerDistance*100 / imageSizeFrontGround))
gsdField.text = gsd.toFixed(1)
sideOverlapField.text = sideOverlap.toFixed(0)
frontalOverlapField.text = frontOverlap.toFixed(0)
missionItem.groundResolution.rawValue = groundResolution
missionItem.sideOverlap.rawValue = sideOverlap
missionItem.frontalOverlap.rawValue = frontOverlap
}
*/
function polygonCaptureStarted() {
missionItem.clearPolygon()
missionItem.clearPolygon()
}
function polygonCaptureFinished(coordinates) {
@ -176,15 +216,42 @@ Rectangle { @@ -176,15 +216,42 @@ Rectangle {
function polygonAdjustStarted() { }
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 }
ExclusiveGroup {
id: cameraOrientationGroup
onCurrentChanged: {
recalcFromMissionValues()
id: cameraOrientationGroup
onCurrentChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
recalcFromCameraValues()
}
}
}
ExclusiveGroup { id: fixedValueGroup }
Column {
id: editorColumn
anchors.margins: _margin
@ -198,307 +265,292 @@ Rectangle { @@ -198,307 +265,292 @@ Rectangle {
anchors.right: parent.right
wrapMode: Text.WordWrap
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 {
model: [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
QGCLabel { text: qsTr("Camera:") }
Item {
anchors.left: parent.left
anchors.right: parent.right
height: textField.height
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCLabel {
anchors.baseline: textField.baseline
anchors.left: parent.left
text: modelData.name + ":"
QGCComboBox {
id: gridTypeCombo
anchors.left: parent.left
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 {
id: textField
anchors.right: parent.right
width: _editFieldWidth
showUnits: true
fact: modelData
onEditingFinished: recalcFromMissionValues()
validator: DoubleValidator{bottom:0.0; decimals:2}
onActivated: {
if (index == _gridTypeManual) {
missionItem.manualGrid = true
} else {
missionItem.manualGrid = false
missionItem.camera = gridTypeCombo.textAt(index)
_noCameraValueRecalc = true
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
text: qsTr("Relative altitude")
checked: missionItem.gridAltitudeRelative
onClicked: missionItem.gridAltitudeRelative = checked
}
anchors.right: parent.right
spacing: _margin
visible: gridTypeCombo.currentIndex != _gridTypeManual
Grid {
columns: 2
columnSpacing: ScreenTools.defaultFontPixelWidth
rowSpacing: _margin
verticalItemAlignment: Grid.AlignVCenter
Row {
spacing: _margin
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}
}
QGCRadioButton {
id: cameraOrientationLandscape
width: _editFieldWidth
text: "Landscape"
checked: true
exclusiveGroup: cameraOrientationGroup
}
QGCLabel { text: qsTr("Frontal Overlap:") }
QGCTextField {
id: frontalOverlapField
width: _editFieldWidth
unitsLabel: "%"
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: IntValidator {bottom:0}
QGCRadioButton {
id: cameraOrientationPortrait
text: "Portrait"
exclusiveGroup: cameraOrientationGroup
}
}
QGCLabel { text: qsTr("Side Overlap:") }
QGCTextField {
id: sideOverlapField
width: _editFieldWidth
unitsLabel: "%"
showUnits: true
onEditingFinished: recalcFromCameraValues()
validator: IntValidator {bottom:0}
}
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: gridTypeCombo.currentIndex == _gridTypeCustomCamera
Component.onCompleted: recalcFromMissionValues()
}
GridLayout {
columns: 3
columnSpacing: _margin
rowSpacing: _margin
QGCLabel { text: qsTr("Camera:") }
property real _fieldWidth: ScreenTools.defaultFontPixelWidth * 10
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCLabel { }
QGCLabel { text: qsTr("Width") }
QGCLabel { text: qsTr("Height") }
Grid {
columns: 2
spacing: ScreenTools.defaultFontPixelWidth
verticalItemAlignment: Grid.AlignVCenter
QGCRadioButton {
id: cameraOrientationLandscape
width: _editFieldWidth
text: "Landscape"
checked: true
exclusiveGroup: cameraOrientationGroup
QGCLabel { text: qsTr("Sensor:") }
FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraSensorWidth
}
FactTextField {
Layout.preferredWidth: parent._fieldWidth
fact: missionItem.cameraSensorHeight
}
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 {
id: cameraOrientationPortrait
text: "Portrait"
exclusiveGroup: cameraOrientationGroup
QGCLabel { text: qsTr("Grid:") }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCCheckBox {
id: cameraTrigger
width: _editFieldWidth
text: qsTr("Trigger:")
checked: missionItem.cameraTrigger
onClicked: missionItem.cameraTrigger = checked
FactTextFieldGrid {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
factList: [ missionItem.gridAngle, missionItem.turnaroundDist ]
}
FactTextField {
width: _editFieldWidth
showUnits: true
fact: missionItem.cameraTriggerDistance
enabled: missionItem.cameraTrigger
onEditingFinished: recalcFromMissionValues()
validator: DoubleValidator{bottom:0.0; decimals:2}
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:")
}
}
Component {
id: cameraFields
QGCViewDialog {
Column {
id: dialogColumn
anchors.margins: _margin
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin * 5
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
}
}
}
}
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
}
Grid {
columns: 2
spacing: ScreenTools.defaultFontPixelWidth
verticalItemAlignment: Grid.AlignVCenter
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))
}
}
}
}
FactTextField {
id: gridAltitudeField
Layout.fillWidth: true
fact: missionItem.gridAltitude
enabled: fixedAltitudeRadio.checked
}
}
function accept() {
hideDialog()
recalcFromCameraValues()
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
}
}//QGCViewDialog
}//Component
FactTextField {
id: groundResolutionField
Layout.fillWidth: true
fact: missionItem.groundResolution
enabled: fixedGroundResolutionRadio.checked
}
}
}
// Manual grid ui
Column {
spacing: ScreenTools.defaultFontPixelHeight*0.01
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: gridTypeCombo.currentIndex == _gridTypeManual
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel { text: qsTr("Grid:") }
QGCLabel { text: qsTr("Model:") }
QGCLabel { text: cameraModelList.get(cameraIndex).text }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
Grid {
columns: 2
columnSpacing: ScreenTools.defaultFontPixelWidth
rowSpacing: ScreenTools.defaultFontPixelHeight*0.01
FactTextFieldGrid {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
factList: [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
}
QGCLabel {
text: qsTr("Sensor Size:")
width: _editFieldWidth
}
QGCLabel {
text: cameraModelList.get(cameraIndex).sensorWidth.toFixed(2) + qsTr(" x ") + cameraModelList.get(cameraIndex).sensorHeight.toFixed(2)
width: _editFieldWidth
}
QGCCheckBox {
anchors.left: parent.left
text: qsTr("Relative altitude")
checked: missionItem.gridAltitudeRelative
onClicked: missionItem.gridAltitudeRelative = checked
}
QGCLabel { text: qsTr("Image Size:") }
QGCLabel { text: cameraModelList.get(cameraIndex).imageWidth.toFixed(0) + qsTr(" x ") + cameraModelList.get(cameraIndex).imageHeight.toFixed(0) }
QGCLabel { text: qsTr("Camera:") }
QGCLabel { text: qsTr("Focal length:") }
QGCLabel { text: cameraModelList.get(cameraIndex).focalLength.toFixed(2) }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
}
QGCButton {
id: cameraModelChange
text: qsTr("Change")
RowLayout {
anchors.left: parent.left
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: {
qgcView.showDialog(cameraFields, qsTr("Set Camera Model"), qgcView.showDialogDefaultWidth, StandardButton.Save)
FactTextField {
id: cameraTriggerDistanceField
Layout.fillWidth: true
fact: missionItem.cameraTriggerDistance
enabled: missionItem.cameraTrigger
}
}
}
QGCLabel { text: qsTr("Polygon:") }
Rectangle {

67
src/MissionManager/Survey.FactMetaData.json

@ -18,20 +18,85 @@ @@ -18,20 +18,85 @@
"shortDescription": "Amount of spacing in between parallel grid lines.",
"type": "double",
"decimalPlaces": 2,
"min": 0.1,
"units": "m"
},
{
"name": "Turnaround dist.",
"name": "Turnaround dist",
"shortDescription": "Amount of additional distance to add outside the grid area for vehicle turnaround.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"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",
"shortDescription": "Distance between each triggering of the camera.",
"type": "double",
"decimalPlaces": 2,
"min": 0.1,
"units": "m"
}
]

285
src/MissionManager/SurveyMissionItem.cc

@ -17,22 +17,44 @@ @@ -17,22 +17,44 @@
QGC_LOGGING_CATEGORY(SurveyMissionItemLog, "SurveyMissionItemLog")
const char* SurveyMissionItem::_jsonTypeKey = "type";
const char* SurveyMissionItem::_jsonPolygonKey = "polygon";
const char* SurveyMissionItem::_jsonIdKey = "id";
const char* SurveyMissionItem::_jsonGridAltitudeKey = "gridAltitude";
const char* SurveyMissionItem::_jsonGridAltitudeRelativeKey = "gridAltitudeRelative";
const char* SurveyMissionItem::_jsonGridAngleKey = "gridAngle";
const char* SurveyMissionItem::_jsonGridSpacingKey = "gridSpacing";
const char* SurveyMissionItem::_jsonTurnaroundDistKey = "turnaroundDist";
const char* SurveyMissionItem::_jsonCameraTriggerKey = "cameraTrigger";
const char* SurveyMissionItem::_jsonCameraTriggerDistanceKey = "cameraTriggerDistance";
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::_jsonTypeKey = "type";
const char* SurveyMissionItem::_jsonPolygonObjectKey = "polygon";
const char* SurveyMissionItem::_jsonIdKey = "id";
const char* SurveyMissionItem::_jsonGridObjectKey = "grid";
const char* SurveyMissionItem::_jsonGridAltitudeKey = "altitude";
const char* SurveyMissionItem::_jsonGridAltitudeRelativeKey = "relativeAltitude";
const char* SurveyMissionItem::_jsonGridAngleKey = "angle";
const char* SurveyMissionItem::_jsonGridSpacingKey = "spacing";
const char* SurveyMissionItem::_jsonTurnaroundDistKey = "turnAroundDistance";
const char* SurveyMissionItem::_jsonCameraTriggerKey = "cameraTrigger";
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::_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";
@ -44,29 +66,57 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent) @@ -44,29 +66,57 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
, _dirty(false)
, _cameraTrigger(true)
, _gridAltitudeRelative(true)
, _manualGrid(true)
, _cameraOrientationLandscape(true)
, _fixedValueIsAltitude(false)
, _surveyDistance(0.0)
, _cameraShots(0)
, _coveredArea(0.0)
, _gridAltitudeFact (0, _gridAltitudeFactName, FactMetaData::valueTypeDouble)
, _gridAngleFact (0, _gridAngleFactName, FactMetaData::valueTypeDouble)
, _gridSpacingFact (0, _gridSpacingFactName, FactMetaData::valueTypeDouble)
, _turnaroundDistFact (0, _turnaroundDistFactName, FactMetaData::valueTypeDouble)
, _cameraTriggerDistanceFact(0, _cameraTriggerDistanceFactName, FactMetaData::valueTypeDouble)
, _gridAltitudeFact (0, _gridAltitudeFactName, FactMetaData::valueTypeDouble)
, _gridAngleFact (0, _gridAngleFactName, FactMetaData::valueTypeDouble)
, _gridSpacingFact (0, _gridSpacingFactName, FactMetaData::valueTypeDouble)
, _turnaroundDistFact (0, _turnaroundDistFactName, 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()) {
_metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/Survey.FactMetaData.json"), NULL /* metaDataParent */);
}
_gridAltitudeFact.setRawValue(50);
_gridSpacingFact.setRawValue(10);
_turnaroundDistFact.setRawValue(60);
_gridSpacingFact.setRawValue(30);
_turnaroundDistFact.setRawValue(_vehicle->multiRotor() ? 0 : 60);
_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]);
_gridAngleFact.setMetaData(_metaDataMap[_gridAngleFactName]);
_gridSpacingFact.setMetaData(_metaDataMap[_gridSpacingFactName]);
_turnaroundDistFact.setMetaData(_metaDataMap[_turnaroundDistFactName]);
_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(&_gridAngleFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid);
@ -74,18 +124,17 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent) @@ -74,18 +124,17 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
connect(&_cameraTriggerDistanceFact, &Fact::valueChanged, this, &SurveyMissionItem::_generateGrid);
connect(&_gridAltitudeFact, &Fact::valueChanged, this, &SurveyMissionItem::_updateCoordinateAltitude);
connect(this, &SurveyMissionItem::cameraTriggerChanged, this, &SurveyMissionItem::_cameraTriggerChanged);
}
const SurveyMissionItem& SurveyMissionItem::operator=(const SurveyMissionItem& other)
{
ComplexMissionItem::operator=(other);
_setSurveyDistance(other._surveyDistance);
_setCameraShots(other._cameraShots);
_setCoveredArea(other._coveredArea);
// 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);
connect(&_sideOverlapFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_cameraSensorWidthFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_cameraSensorHeightFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_cameraResolutionWidthFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_cameraResolutionHeightFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
connect(&_cameraFocalLengthFact, &Fact::valueChanged, this, &SurveyMissionItem::_cameraValueChanged);
return *this;
connect(this, &SurveyMissionItem::cameraTriggerChanged, this, &SurveyMissionItem::_cameraTriggerChanged);
}
void SurveyMissionItem::_setSurveyDistance(double surveyDistance)
@ -190,16 +239,41 @@ void SurveyMissionItem::setDirty(bool dirty) @@ -190,16 +239,41 @@ void SurveyMissionItem::setDirty(bool dirty)
void SurveyMissionItem::save(QJsonObject& saveObject) const
{
saveObject[JsonHelper::jsonVersionKey] = 1;
saveObject[JsonHelper::jsonVersionKey] = 2;
saveObject[_jsonTypeKey] = _complexType;
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[_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
@ -213,7 +287,7 @@ void SurveyMissionItem::save(QJsonObject& saveObject) const @@ -213,7 +287,7 @@ void SurveyMissionItem::save(QJsonObject& saveObject) const
polygonArray += jsonValue;
}
saveObject[_jsonPolygonKey] = polygonArray;
saveObject[_jsonPolygonObjectKey] = polygonArray;
}
void SurveyMissionItem::setSequenceNumber(int sequenceNumber)
@ -234,55 +308,115 @@ void SurveyMissionItem::_clear(void) @@ -234,55 +308,115 @@ void SurveyMissionItem::_clear(void)
bool SurveyMissionItem::load(const QJsonObject& complexObject, QString& errorString)
{
_clear();
// Validate requires keys
QStringList requiredKeys;
requiredKeys << JsonHelper::jsonVersionKey << _jsonTypeKey << _jsonIdKey << _jsonPolygonKey << _jsonGridAltitudeKey << _jsonGridAngleKey << _jsonGridSpacingKey <<
_jsonCameraTriggerKey << _jsonCameraTriggerDistanceKey << _jsonGridAltitudeRelativeKey;
if (!JsonHelper::validateRequiredKeys(complexObject, requiredKeys, errorString)) {
_clear();
struct jsonKeyInfo_s {
const char* key;
QJsonValue::Type type;
bool required;
};
QList<JsonHelper::KeyValidateInfo> mainKeyInfoList = {
{ 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;
}
// 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();
if (!JsonHelper::validateKeys(complexObject[_jsonGridObjectKey].toObject(), gridKeyInfoList, errorString)) {
return false;
}
// 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");
_clear();
return false;
}
QString complexType = complexObject[_jsonTypeKey].toString();
if (complexType != _complexType) {
errorString = tr("QGroundControl does not support loading this complex mission item type: %1").arg(complexType);
_clear();
return false;
}
_clear();
setSequenceNumber(complexObject[_jsonIdKey].toInt());
_cameraTrigger = complexObject[_jsonCameraTriggerKey].toBool();
_gridAltitudeRelative = complexObject[_jsonGridAltitudeRelativeKey].toBool();
_manualGrid = complexObject[_jsonManualGridKey].toBool(true);
_cameraTrigger = complexObject[_jsonCameraTriggerKey].toBool(false);
_fixedValueIsAltitude = complexObject[_jsonFixedValueIsAltitudeKey].toBool(true);
_gridAltitudeRelative = complexObject[_jsonGridAltitudeRelativeKey].toBool(true);
_gridAltitudeFact.setRawValue (complexObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (complexObject[_jsonGridAngleKey].toDouble());
_gridSpacingFact.setRawValue (complexObject[_jsonGridSpacingKey].toDouble());
_turnaroundDistFact.setRawValue (complexObject[_jsonTurnaroundDistKey].toDouble());
_cameraTriggerDistanceFact.setRawValue (complexObject[_jsonCameraTriggerDistanceKey].toDouble());
QJsonObject gridObject = complexObject[_jsonGridObjectKey].toObject();
_gridAltitudeFact.setRawValue (gridObject[_jsonGridAltitudeKey].toDouble());
_gridAngleFact.setRawValue (gridObject[_jsonGridAngleKey].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
QJsonArray polygonArray(complexObject[_jsonPolygonKey].toArray());
QJsonArray polygonArray(complexObject[_jsonPolygonObjectKey].toArray());
for (int i=0; i<polygonArray.count(); i++) {
const QJsonValue& pointValue = polygonArray[i];
@ -528,6 +662,9 @@ void SurveyMissionItem::_adjustLineDirection(const QList<QLineF>& lineList, QLis @@ -528,6 +662,9 @@ void SurveyMissionItem::_adjustLineDirection(const QList<QLineF>& lineList, QLis
void SurveyMissionItem::_gridGenerator(const QList<QPointF>& polygonPoints, QList<QPointF>& gridPoints)
{
double gridAngle = _gridAngleFact.rawValue().toDouble();
double gridSpacing = _gridSpacingFact.rawValue().toDouble();
qCDebug(SurveyMissionItemLog) << "SurveyMissionItem::_gridGenerator gridSpacing:gridAngle" << gridSpacing << gridAngle;
gridPoints.clear();
@ -557,7 +694,6 @@ void SurveyMissionItem::_gridGenerator(const QList<QPointF>& polygonPoints, QLi @@ -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
// bounding box to guarantee intersection.
QList<QLineF> lineList;
float gridSpacing = _gridSpacingFact.rawValue().toDouble();
float x = largeBoundRect.topLeft().x() - (gridSpacing / 2);
while (x < largeBoundRect.bottomRight().x()) {
float yTop = largeBoundRect.topLeft().y() - 100.0;
@ -671,3 +807,8 @@ int SurveyMissionItem::cameraShots(void) const @@ -671,3 +807,8 @@ int SurveyMissionItem::cameraShots(void) const
{
return _cameraTrigger ? _cameraShots : 0;
}
void SurveyMissionItem::_cameraValueChanged(void)
{
emit cameraValueChanged();
}

143
src/MissionManager/SurveyMissionItem.h

@ -25,19 +25,29 @@ class SurveyMissionItem : public ComplexMissionItem @@ -25,19 +25,29 @@ class SurveyMissionItem : public ComplexMissionItem
public:
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* gridAngle READ gridAngle CONSTANT)
Q_PROPERTY(Fact* gridSpacing READ gridSpacing CONSTANT)
Q_PROPERTY(Fact* turnaroundDist READ turnaroundDist CONSTANT)
Q_PROPERTY(bool cameraTrigger MEMBER _cameraTrigger NOTIFY cameraTriggerChanged)
Q_PROPERTY(Fact* cameraTriggerDistance READ cameraTriggerDistance 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(Fact* gridAltitude READ gridAltitude CONSTANT)
Q_PROPERTY(bool gridAltitudeRelative MEMBER _gridAltitudeRelative NOTIFY gridAltitudeRelativeChanged)
Q_PROPERTY(Fact* gridAngle READ gridAngle CONSTANT)
Q_PROPERTY(Fact* gridSpacing READ gridSpacing CONSTANT)
Q_PROPERTY(Fact* turnaroundDist READ turnaroundDist CONSTANT)
Q_PROPERTY(bool cameraTrigger MEMBER _cameraTrigger NOTIFY cameraTriggerChanged)
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 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 addPolygonCoordinate(const QGeoCoordinate coordinate);
@ -46,11 +56,19 @@ public: @@ -46,11 +56,19 @@ public:
QVariantList polygonPath(void) { return _polygonPath; }
QVariantList gridPoints (void) { return _gridPoints; }
Fact* gridAltitude(void) { return &_gridAltitudeFact; }
Fact* gridAngle(void) { return &_gridAngleFact; }
Fact* gridSpacing(void) { return &_gridSpacingFact; }
Fact* turnaroundDist(void) { return &_turnaroundDistFact; }
Fact* cameraTriggerDistance(void) { return &_cameraTriggerDistanceFact; }
Fact* gridAltitude (void) { return &_gridAltitudeFact; }
Fact* gridAngle (void) { return &_gridAngleFact; }
Fact* gridSpacing (void) { return &_gridSpacingFact; }
Fact* turnaroundDist (void) { return &_turnaroundDistFact; }
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;
double coveredArea(void) const { return _coveredArea; }
@ -87,14 +105,20 @@ public: @@ -87,14 +105,20 @@ public:
void save (QJsonObject& saveObject) const final;
signals:
void polygonPathChanged (void);
void altitudeChanged (double altitude);
void gridAngleChanged (double gridAngle);
void gridPointsChanged (void);
void cameraTriggerChanged (bool cameraTrigger);
void gridAltitudeRelativeChanged (bool gridAltitudeRelative);
void cameraShotsChanged (int cameraShots);
void coveredAreaChanged (double coveredArea);
void polygonPathChanged (void);
void altitudeChanged (double altitude);
void gridAngleChanged (double gridAngle);
void gridPointsChanged (void);
void cameraTriggerChanged (bool cameraTrigger);
void gridAltitudeRelativeChanged (bool gridAltitudeRelative);
void cameraShotsChanged (int cameraShots);
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:
void _cameraTriggerChanged(void);
@ -113,33 +137,46 @@ private: @@ -113,33 +137,46 @@ private:
void _setSurveyDistance(double surveyDistance);
void _setCameraShots(int cameraShots);
void _setCoveredArea(double coveredArea);
int _sequenceNumber;
bool _dirty;
QVariantList _polygonPath;
QVariantList _gridPoints;
QGeoCoordinate _coordinate;
QGeoCoordinate _exitCoordinate;
double _altitude;
double _gridAngle;
bool _cameraTrigger;
bool _gridAltitudeRelative;
double _surveyDistance;
int _cameraShots;
double _coveredArea;
void _cameraValueChanged(void);
int _sequenceNumber;
bool _dirty;
QVariantList _polygonPath;
QVariantList _gridPoints;
QGeoCoordinate _coordinate;
QGeoCoordinate _exitCoordinate;
double _altitude;
bool _cameraTrigger;
bool _gridAltitudeRelative;
bool _manualGrid;
QString _camera;
bool _cameraOrientationLandscape;
bool _fixedValueIsAltitude;
double _surveyDistance;
int _cameraShots;
double _coveredArea;
Fact _gridAltitudeFact;
Fact _gridAngleFact;
Fact _gridSpacingFact;
Fact _turnaroundDistFact;
Fact _cameraTriggerDistanceFact;
Fact _groundResolutionFact;
Fact _frontalOverlapFact;
Fact _sideOverlapFact;
Fact _cameraSensorWidthFact;
Fact _cameraSensorHeightFact;
Fact _cameraResolutionWidthFact;
Fact _cameraResolutionHeightFact;
Fact _cameraFocalLengthFact;
static QMap<QString, FactMetaData*> _metaDataMap;
static const char* _jsonTypeKey;
static const char* _jsonPolygonKey;
static const char* _jsonPolygonObjectKey;
static const char* _jsonIdKey;
static const char* _jsonGridObjectKey;
static const char* _jsonGridAltitudeKey;
static const char* _jsonGridAltitudeRelativeKey;
static const char* _jsonGridAngleKey;
@ -147,12 +184,34 @@ private: @@ -147,12 +184,34 @@ private:
static const char* _jsonTurnaroundDistKey;
static const char* _jsonCameraTriggerKey;
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* _gridAngleFactName;
static const char* _gridSpacingFactName;
static const char* _turnaroundDistFactName;
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;
};

Loading…
Cancel
Save