Newer
Older
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.4
import QGroundControl.ScreenTools 1.0
import QGroundControl.Vehicle 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
// Editor for Survery mission items
Rectangle {
id: _root
height: visible ? (editorColumn.height + (_margin * 2)) : 0
width: availableWidth
color: qgcPal.windowShadeDark
radius: _radius
// The following properties must be available up the hierarchy chain
//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 _fieldWidth: ScreenTools.defaultFontPixelWidth * 10.5
property var _cameraList: [ qsTr("Manual Grid (no camera specs)"), qsTr("Custom Camera Grid") ]
property var _vehicle: QGroundControl.multiVehicleManager.activeVehicle ? QGroundControl.multiVehicleManager.activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
property var _vehicleCameraList: _vehicle.cameraList
readonly property int _gridTypeManual: 0
readonly property int _gridTypeCustomCamera: 1
readonly property int _gridTypeCamera: 2
Component.onCompleted: {
for (var i=0; i<_vehicle.cameraList.length; i++) {
_cameraList.push(_vehicle.cameraList[i].name)
gridTypeCombo.model = _cameraList
gridTypeCombo.currentIndex = _gridTypeManual
} else {
var index = -1
for (index=0; index<_cameraList.length; index++) {
if (_cameraList[index] == missionItem.camera.value) {
break;
}
}
missionItem.cameraOrientationFixed = false
if (index == -1) {
gridTypeCombo.currentIndex = _gridTypeManual
} else {
gridTypeCombo.currentIndex = index
if (index != 1) {
// Specific camera is selected
missionItem.cameraOrientationFixed = _vehicleCameraList[index - _gridTypeCamera].fixedOrientation
}
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) {
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
if (missionItem.fixedValueIsAltitude.value) {
groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
} else {
altitude = (imageWidth * groundResolution * focalLength) / (sensorWidth * 100)
}
if (missionItem.cameraOrientationLandscape.value) {
imageSizeSideGround = (imageWidth * groundResolution) / 100
imageSizeFrontGround = (imageHeight * groundResolution) / 100
imageSizeSideGround = (imageHeight * groundResolution) / 100
imageSizeFrontGround = (imageWidth * groundResolution) / 100
gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 )
cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 )
if (missionItem.fixedValueIsAltitude.value) {
missionItem.groundResolution.rawValue = groundResolution
} else {
missionItem.gridAltitude.rawValue = altitude
}
missionItem.gridSpacing.rawValue = gridSpacing
missionItem.cameraTriggerDistance.rawValue = cameraTriggerDistance
}
function polygonCaptureFinished(coordinates) {
for (var i=0; i<coordinates.length; i++) {
missionItem.addPolygonCoordinate(coordinates[i])
function polygonAdjustVertex(vertexIndex, vertexCoordinate) {
missionItem.adjustPolygonCoordinate(vertexIndex, vertexCoordinate)
function polygonAdjustStarted() { }
function polygonAdjustFinished() { }
property bool _noCameraValueRecalc: false ///< Prevents uneeded recalcs
Connections {
target: missionItem.camera
onValueChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && !_noCameraValueRecalc) {
recalcFromCameraValues()
}
}
}
Connections {
target: missionItem.gridAltitude
onValueChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && missionItem.fixedValueIsAltitude.value && !_noCameraValueRecalc) {
recalcFromCameraValues()
}
}
}
Connections {
target: missionItem
onCameraValueChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && !_noCameraValueRecalc) {
QGCPalette { id: qgcPal; colorGroupEnabled: true }
id: cameraOrientationGroup
onCurrentChanged: {
if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
recalcFromCameraValues()
}
Column {
id: editorColumn
anchors.margins: _margin
anchors.top: parent.top
anchors.left: parent.left
text: qsTr("Camera")
showSpacer: false
}
anchors.left: parent.left
anchors.right: parent.right
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
spacing: _margin
visible: cameraHeader.checked
QGCComboBox {
id: gridTypeCombo
anchors.left: parent.left
anchors.right: parent.right
model: _cameraList
currentIndex: -1
onActivated: {
if (index == _gridTypeManual) {
missionItem.manualGrid.value = true
} else if (index == _gridTypeCustomCamera) {
missionItem.manualGrid.value = false
missionItem.camera.value = gridTypeCombo.textAt(index)
missionItem.cameraOrientationFixed = false
} else {
missionItem.manualGrid.value = false
missionItem.camera.value = gridTypeCombo.textAt(index)
_noCameraValueRecalc = true
var listIndex = index - _gridTypeCamera
missionItem.cameraSensorWidth.rawValue = _vehicleCameraList[listIndex].sensorWidth
missionItem.cameraSensorHeight.rawValue = _vehicleCameraList[listIndex].sensorHeight
missionItem.cameraResolutionWidth.rawValue = _vehicleCameraList[listIndex].imageWidth
missionItem.cameraResolutionHeight.rawValue = _vehicleCameraList[listIndex].imageHeight
missionItem.cameraFocalLength.rawValue = _vehicleCameraList[listIndex].focalLength
missionItem.cameraOrientationLandscape.rawValue = _vehicleCameraList[listIndex].landscape ? 1 : 0
missionItem.cameraOrientationFixed = _vehicleCameraList[listIndex].fixedOrientation
_noCameraValueRecalc = false
recalcFromCameraValues()
}
}
}
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: missionItem.manualGrid.value == true
QGCCheckBox {
id: cameraTriggerDistanceCheckBox
anchors.baseline: cameraTriggerDistanceField.baseline
text: qsTr("Trigger Distance")
checked: missionItem.cameraTriggerDistance.rawValue > 0
onClicked: {
if (checked) {
missionItem.cameraTriggerDistance.value = missionItem.cameraTriggerDistance.defaultValue
} else {
missionItem.cameraTriggerDistance.value = 0
}
}
}
FactTextField {
id: cameraTriggerDistanceField
Layout.fillWidth: true
fact: missionItem.cameraTriggerDistance
enabled: cameraTriggerDistanceCheckBox.checked
text: qsTr("Hover and capture image")
fact: missionItem.hoverAndCapture
visible: missionItem.hoverAndCaptureAllowed
anchors.right: parent.right
spacing: _margin
visible: gridTypeCombo.currentIndex != _gridTypeManual
spacing: _margin
anchors.horizontalCenter: parent.horizontalCenter
visible: !missionItem.cameraOrientationFixed
QGCRadioButton {
width: _editFieldWidth
text: "Landscape"
checked: !!missionItem.cameraOrientationLandscape.value
onClicked: missionItem.cameraOrientationLandscape.value = 1
QGCRadioButton {
id: cameraOrientationPortrait
text: "Portrait"
checked: !missionItem.cameraOrientationLandscape.value
onClicked: missionItem.cameraOrientationLandscape.value = 0
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: gridTypeCombo.currentIndex === _gridTypeCustomCamera
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
Item { Layout.fillWidth: true }
QGCLabel {
Layout.preferredWidth: _root._fieldWidth
text: qsTr("Width")
}
QGCLabel {
Layout.preferredWidth: _root._fieldWidth
text: qsTr("Height")
}
}
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCLabel { text: qsTr("Sensor"); Layout.fillWidth: true }
Layout.preferredWidth: _root._fieldWidth
fact: missionItem.cameraSensorWidth
}
FactTextField {
Layout.preferredWidth: _root._fieldWidth
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCLabel { text: qsTr("Image"); Layout.fillWidth: true }
Layout.preferredWidth: _root._fieldWidth
fact: missionItem.cameraResolutionWidth
}
FactTextField {
Layout.preferredWidth: _root._fieldWidth
fact: missionItem.cameraResolutionHeight
}
}
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCLabel {
Layout.fillWidth: true
}
FactTextField {
Layout.preferredWidth: _root._fieldWidth
fact: missionItem.cameraFocalLength
}
} // Column - custom camera
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
Item { Layout.fillWidth: true }
QGCLabel {
Layout.preferredWidth: _root._fieldWidth
text: qsTr("Frontal")
Layout.preferredWidth: _root._fieldWidth
text: qsTr("Side")
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCLabel { text: qsTr("Overlap"); Layout.fillWidth: true }
Layout.preferredWidth: _root._fieldWidth
fact: missionItem.frontalOverlap
Layout.preferredWidth: _root._fieldWidth
fact: missionItem.sideOverlap
SectionHeader {
id: gridHeader
text: qsTr("Grid")
}
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 2
GridLayout {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 3
visible: gridHeader.checked
QGCLabel {
id: angleText
text: qsTr("Angle")
}
Item { Layout.fillWidth: true }
property var activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
ToolButton {
id: windRoseButton
anchors.verticalCenter: angleText.verticalCenter
iconSource: qgcPal.globalTheme === QGCPalette.Light ? "/res/wind-roseBlack.svg" : "/res/wind-rose.svg"
visible: _activeVehicle ? _activeVehicle.fixedWing : true
onClicked: {
var cords = windRoseButton.mapToItem(_root, 0, 0)
windRosePie.popup(cords.x + windRoseButton.width / 2, cords.y + windRoseButton.height / 2);
fact: missionItem.gridAngle
Layout.fillWidth: true
QGCLabel { text: qsTr("Turnaround dist") }
FactTextField {
fact: missionItem.turnaroundDist
QGCCheckBox {
text: qsTr("Refly at 90 degree offset")
checked: missionItem.refly90Degrees
onClicked: missionItem.refly90Degrees = checked
Layout.columnSpan: 2
}
checked: !!missionItem.fixedValueIsAltitude.value
exclusiveGroup: fixedValueGroup
onClicked: missionItem.fixedValueIsAltitude.value = 1
fact: missionItem.gridAltitude
enabled: fixedAltitudeRadio.checked
id: fixedGroundResolutionRadio
checked: !missionItem.fixedValueIsAltitude.value
exclusiveGroup: fixedValueGroup
onClicked: missionItem.fixedValueIsAltitude.value = 0
fact: missionItem.groundResolution
enabled: fixedGroundResolutionRadio.checked
SectionHeader {
id: manualGridHeader
text: qsTr("Grid")
visible: gridTypeCombo.currentIndex == _gridTypeManual
}
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
visible: manualGridHeader.visible && manualGridHeader.checked
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
GridLayout {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: _margin
rowSpacing: _margin
columns: 4
visible: gridHeader.checked
QGCLabel {
id: manualAngleText
text: qsTr("Angle")
Layout.columnSpan: 1
Layout.fillWidth: true
}
property var activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
ToolButton {
id: manualWindRoseButton
anchors.verticalCenter: manualAngleText.verticalCenter
Layout.columnSpan: 1
iconSource: qgcPal.globalTheme === QGCPalette.Light ? "/res/wind-roseBlack.svg" : "/res/wind-rose.svg"
visible: _activeVehicle ? _activeVehicle.fixedWing : true
onClicked: {
var cords = manualWindRoseButton.mapToItem(_root, 0, 0)
windRosePie.popup(cords.x + manualWindRoseButton.width / 2, cords.y + manualWindRoseButton.height / 2);
}
}
FactTextField {
id: manualGridAngleText
fact: missionItem.gridAngle
Layout.columnSpan: 2
}
}
FactTextFieldGrid {
anchors.left: parent.left
anchors.right: parent.right
columnSpacing: ScreenTools.defaultFontPixelWidth
factList: [ missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
factLabels: [ qsTr("Spacing"), qsTr("Altitude"), qsTr("Turnaround dist")]
QGCCheckBox {
text: qsTr("Refly at 90 degree offset")
checked: missionItem.refly90Degrees
onClicked: missionItem.refly90Degrees = checked
}
anchors.left: parent.left
text: qsTr("Relative altitude")
fact: missionItem.gridAltitudeRelative
SectionHeader {
id: statsHeader
text: qsTr("Statistics") }
columns: 2
columnSpacing: ScreenTools.defaultFontPixelWidth
QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }
QGCLabel { text: missionItem.cameraShots }
QGCLabel {
text: {
var timeVal = missionItem.timeBetweenShots
if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
return qsTr("N/A")
}
return timeVal.toFixed(1) + " " + qsTr("secs")
}
}
id: windRoseArrow
source: "/res/wind-rose-arrow.svg"
visible: windRosePie.visible
width: windRosePie.width / 5
height: width * 1.454
smooth: true
transform: Rotation {
origin.x: windRoseArrow.width / 2
origin.y: windRoseArrow.height / 2
axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle
x: windRosePie.x + Math.sin(- windRosePie.angle*Math.PI/180 - Math.PI/2)*(windRosePie.width/2 - windRoseArrow.width/2) + windRosePie.width / 2 - windRoseArrow.width / 2
y: windRosePie.y + Math.cos(- windRosePie.angle*Math.PI/180 - Math.PI/2)*(windRosePie.width/2 - windRoseArrow.width/2) + windRosePie.height / 2 - windRoseArrow.height / 2
z: windRosePie.z + 1
id: windGuru
source: "/res/wind-guru.svg"
visible: windRosePie.visible
width: windRosePie.width / 3
height: width * 4.28e-1
smooth: true
transform: Rotation {
origin.x: windGuru.width / 2
origin.y: windGuru.height / 2
axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle + 180
}
x: windRosePie.x + Math.sin(- windRosePie.angle*Math.PI/180 - 3*Math.PI/2)*(windRosePie.width/2) + windRosePie.width / 2 - windGuru.width / 2
y: windRosePie.y + Math.cos(- windRosePie.angle*Math.PI/180 - 3*Math.PI/2)*(windRosePie.height/2) + windRosePie.height / 2 - windGuru.height / 2
z: windRosePie.z + 1
Item {
id: windRosePie
height: 2.6*windRoseButton.height
width: 2.6*windRoseButton.width
visible: false
property string colorCircle: qgcPal.windowShade
property string colorBackground: qgcPal.colorGrey
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
property real lineWidth: windRoseButton.width / 3
property real angle: 0
Canvas {
id: windRoseCanvas
anchors.fill: parent
onPaint: {
var ctx = getContext("2d")
var x = width / 2
var y = height / 2
var angleWidth = 0.03 * Math.PI
var start = windRosePie.angle*Math.PI/180 - angleWidth
var end = windRosePie.angle*Math.PI/180 + angleWidth
ctx.reset()
ctx.beginPath();
ctx.arc(x, y, (width / 3) - windRosePie.lineWidth / 2, 0, 2*Math.PI, false)
ctx.lineWidth = windRosePie.lineWidth
ctx.strokeStyle = windRosePie.colorBackground
ctx.stroke()
ctx.beginPath();
ctx.arc(x, y, (width / 3) - windRosePie.lineWidth / 2, start, end, false)
ctx.lineWidth = windRosePie.lineWidth
ctx.strokeStyle = windRosePie.colorCircle
ctx.stroke()
}
onFocusChanged: {
visible = focus
}
function popup(x, y) {
if (x !== undefined)
windRosePie.x = x - windRosePie.width / 2;
if (y !== undefined)
windRosePie.y = y - windRosePie.height / 2;
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
windRosePie.visible = false;
onPositionChanged: {
var point = Qt.point(mouseX - parent.width / 2, mouseY - parent.height / 2)
var angle = Math.round(Math.atan2(point.y, point.x) * 180 / Math.PI)
windRoseCanvas.requestPaint()
windRosePie.angle = angle
gridAngleText.text = angle
gridAngleText.editingFinished();
}
}
}