SurveyItemEditor.qml 30.6 KB
Newer Older
1 2
import QtQuick          2.3
import QtQuick.Controls 1.2
3
import QtQuick.Controls.Styles 1.4
Don Gagne's avatar
Don Gagne committed
4
import QtQuick.Dialogs  1.2
5
import QtQuick.Extras   1.4
6
import QtQuick.Layouts  1.2
7

8
import QGroundControl               1.0
9 10 11 12 13
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
14
import QGroundControl.FlightMap     1.0
15 16 17 18

// Editor for Survery mission items
Rectangle {
    id:         _root
19
    height:     visible ? (editorColumn.height + (_margin * 2)) : 0
20 21 22 23
    width:      availableWidth
    color:      qgcPal.windowShadeDark
    radius:     _radius

Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
24
    // The following properties must be available up the hierarchy chain
25 26 27
    //property real   availableWidth    ///< Width for control
    //property var    missionItem       ///< Mission Item for editor

28
    property real   _margin:            ScreenTools.defaultFontPixelWidth / 2
29 30 31 32
    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
33
    property var    _vehicleCameraList: _vehicle ? _vehicle.staticCameraList : []
Don Gagne's avatar
Don Gagne committed
34 35 36 37 38

    readonly property int _gridTypeManual:          0
    readonly property int _gridTypeCustomCamera:    1
    readonly property int _gridTypeCamera:          2

39
    Component.onCompleted: {
Gus Grubba's avatar
Gus Grubba committed
40 41
        for (var i=0; i<_vehicle.staticCameraList.length; i++) {
            _cameraList.push(_vehicle.staticCameraList[i].name)
Don Gagne's avatar
Don Gagne committed
42
        }
43
        gridTypeCombo.model = _cameraList
44
        if (missionItem.manualGrid.value) {
45 46
            gridTypeCombo.currentIndex = _gridTypeManual
        } else {
47 48 49 50 51 52
            var index = -1
            for (index=0; index<_cameraList.length; index++) {
                if (_cameraList[index] == missionItem.camera.value) {
                    break;
                }
            }
53
            missionItem.cameraOrientationFixed = false
Don Gagne's avatar
Don Gagne committed
54 55
            if (index == _cameraList.length) {
                gridTypeCombo.currentIndex = _gridTypeCustomCamera
56 57
            } else {
                gridTypeCombo.currentIndex = index
58 59
                if (index != 1) {
                    // Specific camera is selected
60 61 62
                    var camera = _vehicleCameraList[index - _gridTypeCamera]
                    missionItem.cameraOrientationFixed = camera.fixedOrientation
                    missionItem.cameraMinTriggerInterval = camera.minTriggerInterval
63
                }
64
            }
Don Gagne's avatar
Don Gagne committed
65
        }
66
        recalcFromCameraValues()
Don Gagne's avatar
Don Gagne committed
67
    }
Don Gagne's avatar
Don Gagne committed
68 69

    function recalcFromCameraValues() {
70 71 72 73 74
        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
Don Gagne's avatar
Don Gagne committed
75

76 77 78 79
        var altitude        = missionItem.gridAltitude.rawValue
        var groundResolution= missionItem.groundResolution.rawValue
        var frontalOverlap  = missionItem.frontalOverlap.rawValue
        var sideOverlap     = missionItem.sideOverlap.rawValue
Don Gagne's avatar
Don Gagne committed
80 81

        if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || groundResolution <= 0) {
Don Gagne's avatar
Don Gagne committed
82 83 84
            return
        }

Don Gagne's avatar
Don Gagne committed
85 86
        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
Don Gagne's avatar
Don Gagne committed
87 88
        var gridSpacing
        var cameraTriggerDistance
89

90
        if (missionItem.fixedValueIsAltitude.value) {
91
            groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
Don Gagne's avatar
Don Gagne committed
92 93 94
        } else {
            altitude = (imageWidth * groundResolution * focalLength) / (sensorWidth * 100)
        }
95

96
        if (missionItem.cameraOrientationLandscape.value) {
97
            imageSizeSideGround  = (imageWidth  * groundResolution) / 100
Don Gagne's avatar
Don Gagne committed
98
            imageSizeFrontGround = (imageHeight * groundResolution) / 100
Don Gagne's avatar
Don Gagne committed
99
        } else {
100 101
            imageSizeSideGround  = (imageHeight * groundResolution) / 100
            imageSizeFrontGround = (imageWidth  * groundResolution) / 100
Don Gagne's avatar
Don Gagne committed
102 103
        }

104 105 106
        gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 )
        cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 )

107
        if (missionItem.fixedValueIsAltitude.value) {
Don Gagne's avatar
Don Gagne committed
108 109 110 111
            missionItem.groundResolution.rawValue = groundResolution
        } else {
            missionItem.gridAltitude.rawValue = altitude
        }
Don Gagne's avatar
Don Gagne committed
112 113 114 115
        missionItem.gridSpacing.rawValue = gridSpacing
        missionItem.cameraTriggerDistance.rawValue = cameraTriggerDistance
    }

116
    function polygonCaptureStarted() {
Don Gagne's avatar
Don Gagne committed
117
        missionItem.clearPolygon()
118
    }
Don Gagne's avatar
Don Gagne committed
119

120 121 122
    function polygonCaptureFinished(coordinates) {
        for (var i=0; i<coordinates.length; i++) {
            missionItem.addPolygonCoordinate(coordinates[i])
Don Gagne's avatar
Don Gagne committed
123
        }
124
    }
Don Gagne's avatar
Don Gagne committed
125

126 127
    function polygonAdjustVertex(vertexIndex, vertexCoordinate) {
        missionItem.adjustPolygonCoordinate(vertexIndex, vertexCoordinate)
Don Gagne's avatar
Don Gagne committed
128 129
    }

130 131 132
    function polygonAdjustStarted() { }
    function polygonAdjustFinished() { }

Don Gagne's avatar
Don Gagne committed
133 134
    property bool _noCameraValueRecalc: false   ///< Prevents uneeded recalcs

135 136 137 138 139 140 141 142 143 144
    Connections {
        target: missionItem.camera

        onValueChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && !_noCameraValueRecalc) {
                recalcFromCameraValues()
            }
        }
    }

Don Gagne's avatar
Don Gagne committed
145 146 147 148
    Connections {
        target: missionItem.gridAltitude

        onValueChanged: {
149
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && missionItem.fixedValueIsAltitude.value && !_noCameraValueRecalc) {
150 151 152 153 154 155 156 157 158 159
                recalcFromCameraValues()
            }
        }
    }

    Connections {
        target: missionItem

        onCameraValueChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && !_noCameraValueRecalc) {
Don Gagne's avatar
Don Gagne committed
160 161 162 163 164
                recalcFromCameraValues()
            }
        }
    }

165 166
    QGCPalette { id: qgcPal; colorGroupEnabled: true }

Don Gagne's avatar
Don Gagne committed
167
    ExclusiveGroup {
Don Gagne's avatar
Don Gagne committed
168 169 170 171 172 173
        id: cameraOrientationGroup

        onCurrentChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
                recalcFromCameraValues()
            }
174
        }
Don Gagne's avatar
Don Gagne committed
175 176
    }

Don Gagne's avatar
Don Gagne committed
177 178
    ExclusiveGroup { id: fixedValueGroup }

179 180 181 182 183
    Column {
        id:                 editorColumn
        anchors.margins:    _margin
        anchors.top:        parent.top
        anchors.left:       parent.left
184
        anchors.right:      parent.right
185 186
        spacing:            _margin

187 188 189 190 191 192 193 194 195
        QGCLabel {
            anchors.left:   parent.left
            anchors.right:  parent.right
            text:           qsTr("WARNING: Photo interval is below minimum interval (%1 secs) supported by camera.").arg(missionItem.cameraMinTriggerInterval.toFixed(1))
            wrapMode:       Text.WordWrap
            color:          qgcPal.warningText
            visible:        missionItem.manualGrid.value !== true && missionItem.cameraShots > 0 && missionItem.cameraMinTriggerInterval !== 0 && missionItem.cameraMinTriggerInterval > missionItem.timeBetweenShots
        }

196
        SectionHeader {
197
            id:         cameraHeader
198 199 200
            text:       qsTr("Camera")
            showSpacer: false
        }
201

202
        Column {
Don Gagne's avatar
Don Gagne committed
203 204
            anchors.left:   parent.left
            anchors.right:  parent.right
205 206 207 208 209 210 211 212 213 214 215 216 217
            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
218
                        missionItem.fixedValueIsAltitude.value = true
219 220 221 222
                    } else if (index == _gridTypeCustomCamera) {
                        missionItem.manualGrid.value = false
                        missionItem.camera.value = gridTypeCombo.textAt(index)
                        missionItem.cameraOrientationFixed = false
223
                        missionItem.cameraMinTriggerInterval = 0
224 225 226 227 228 229 230 231 232 233 234 235
                    } 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
236
                        missionItem.cameraMinTriggerInterval            = _vehicleCameraList[listIndex].minTriggerInterval
237 238 239 240 241 242 243 244 245 246 247 248
                        _noCameraValueRecalc = false
                        recalcFromCameraValues()
                    }
                }
            }

            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
                visible:        missionItem.manualGrid.value == true

249 250
                QGCCheckBox {
                    id:                 cameraTriggerDistanceCheckBox
251 252
                    anchors.baseline:   cameraTriggerDistanceField.baseline
                    text:               qsTr("Trigger Distance")
253 254 255 256 257 258 259 260
                    checked:            missionItem.cameraTriggerDistance.rawValue > 0
                    onClicked: {
                        if (checked) {
                            missionItem.cameraTriggerDistance.value = missionItem.cameraTriggerDistance.defaultValue
                        } else {
                            missionItem.cameraTriggerDistance.value = 0
                        }
                    }
261 262 263 264 265 266
                }

                FactTextField {
                    id:                 cameraTriggerDistanceField
                    Layout.fillWidth:   true
                    fact:               missionItem.cameraTriggerDistance
267
                    enabled:            cameraTriggerDistanceCheckBox.checked
268 269 270 271
                }
            }
        }

Don Gagne's avatar
Don Gagne committed
272 273
        // Camera based grid ui
        Column {
Don Gagne's avatar
Don Gagne committed
274
            anchors.left:   parent.left
Don Gagne's avatar
Don Gagne committed
275 276 277
            anchors.right:  parent.right
            spacing:        _margin
            visible:        gridTypeCombo.currentIndex != _gridTypeManual
Don Gagne's avatar
Don Gagne committed
278

Don Gagne's avatar
Don Gagne committed
279
            Row {
280 281 282
                spacing:                    _margin
                anchors.horizontalCenter:   parent.horizontalCenter
                visible:                    !missionItem.cameraOrientationFixed
283

Don Gagne's avatar
Don Gagne committed
284 285 286
                QGCRadioButton {
                    width:          _editFieldWidth
                    text:           "Landscape"
287
                    checked:        !!missionItem.cameraOrientationLandscape.value
Don Gagne's avatar
Don Gagne committed
288
                    exclusiveGroup: cameraOrientationGroup
289
                    onClicked:      missionItem.cameraOrientationLandscape.value = 1
Don Gagne's avatar
Don Gagne committed
290
                }
291

Don Gagne's avatar
Don Gagne committed
292 293 294
                QGCRadioButton {
                    id:             cameraOrientationPortrait
                    text:           "Portrait"
295
                    checked:        !missionItem.cameraOrientationLandscape.value
Don Gagne's avatar
Don Gagne committed
296
                    exclusiveGroup: cameraOrientationGroup
297
                    onClicked:      missionItem.cameraOrientationLandscape.value = 0
Don Gagne's avatar
Don Gagne committed
298
                }
299 300
            }

Don Gagne's avatar
Don Gagne committed
301
            Column {
302
                id:             custCameraCol
Don Gagne's avatar
Don Gagne committed
303 304 305
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
                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")
                    }
                }
Don Gagne's avatar
Don Gagne committed
322

323 324 325 326
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
327
                    QGCLabel { text: qsTr("Sensor"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
328
                    FactTextField {
329
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
330 331 332
                        fact:                   missionItem.cameraSensorWidth
                    }
                    FactTextField {
333
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
334 335
                        fact:                   missionItem.cameraSensorHeight
                    }
336
                }
Don Gagne's avatar
Don Gagne committed
337

338 339 340 341
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
342
                    QGCLabel { text: qsTr("Image"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
343
                    FactTextField {
344
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
345 346 347
                        fact:                   missionItem.cameraResolutionWidth
                    }
                    FactTextField {
348
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
349 350 351 352
                        fact:                   missionItem.cameraResolutionHeight
                    }
                }

353 354 355 356 357
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
                    QGCLabel {
358
                        text:                   qsTr("Focal length")
359 360 361 362 363 364
                        Layout.fillWidth:       true
                    }
                    FactTextField {
                        Layout.preferredWidth:  _root._fieldWidth
                        fact:                   missionItem.cameraFocalLength
                    }
Don Gagne's avatar
Don Gagne committed
365 366
                }

367
            } // Column - custom camera
Don Gagne's avatar
Don Gagne committed
368

369 370 371
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
Don Gagne's avatar
Don Gagne committed
372
                spacing:        _margin
373 374 375
                Item { Layout.fillWidth: true }
                QGCLabel {
                    Layout.preferredWidth:  _root._fieldWidth
376
                    text:                   qsTr("Front Lap")
Don Gagne's avatar
Don Gagne committed
377 378
                }
                QGCLabel {
379
                    Layout.preferredWidth:  _root._fieldWidth
380
                    text:                   qsTr("Side Lap")
Don Gagne's avatar
Don Gagne committed
381
                }
382
            }
Don Gagne's avatar
Don Gagne committed
383

384 385 386 387
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
388
                QGCLabel { text: qsTr("Overlap"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
389
                FactTextField {
390 391
                    Layout.preferredWidth:  _root._fieldWidth
                    fact:                   missionItem.frontalOverlap
Don Gagne's avatar
Don Gagne committed
392 393
                }
                FactTextField {
394 395
                    Layout.preferredWidth:  _root._fieldWidth
                    fact:                   missionItem.sideOverlap
Don Gagne's avatar
Don Gagne committed
396
                }
Don Gagne's avatar
Don Gagne committed
397 398
            }

399 400 401 402 403 404 405 406 407 408 409 410 411 412
            FactCheckBox {
                text:       qsTr("Hover and capture image")
                fact:       missionItem.hoverAndCapture
                visible:    missionItem.hoverAndCaptureAllowed
                onClicked: {
                    if (checked) {
                        missionItem.cameraTriggerInTurnaround.rawValue = false
                    }
                }
            }

            FactCheckBox {
                text:       qsTr("Take images in turnarounds")
                fact:       missionItem.cameraTriggerInTurnaround
413
                enabled:    missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true
414 415
            }

416 417 418 419
            SectionHeader {
                id:     gridHeader
                text:   qsTr("Grid")
            }
Don Gagne's avatar
Don Gagne committed
420

421
            GridLayout {
Don Gagne's avatar
Don Gagne committed
422 423
                anchors.left:   parent.left
                anchors.right:  parent.right
424 425 426
                columnSpacing:  _margin
                rowSpacing:     _margin
                columns:        2
427
                visible:        gridHeader.checked
428

429 430 431 432 433
                GridLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    columnSpacing:  _margin
                    rowSpacing:     _margin
DonLakeFlyer's avatar
DonLakeFlyer committed
434
                    columns:        2
435 436 437
                    visible:        gridHeader.checked

                    QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
438 439 440
                        id:                 angleText
                        text:               qsTr("Angle")
                        Layout.fillWidth:   true
441 442 443 444 445
                    }

                    ToolButton {
                        id:                     windRoseButton
                        anchors.verticalCenter: angleText.verticalCenter
446
                        iconSource:             qgcPal.globalTheme === QGCPalette.Light ? "/res/wind-roseBlack.svg" : "/res/wind-rose.svg"
447
                        visible:                _vehicle.fixedWing
448 449

                        onClicked: {
450
                            windRosePie.angle = Number(gridAngleText.text)
451
                            var cords = windRoseButton.mapToItem(_root, 0, 0)
452
                            windRosePie.popup(cords.x + windRoseButton.width / 2, cords.y + windRoseButton.height / 2)
453 454 455 456
                        }
                    }
                }

457
                FactTextField {
458
                    id:                 gridAngleText
459 460
                    fact:               missionItem.gridAngle
                    Layout.fillWidth:   true
461 462
                }

463
                QGCLabel { text: qsTr("Turnaround dist") }
464 465
                FactTextField {
                    fact:                   missionItem.turnaroundDist
466
                    Layout.fillWidth:       true
467
                }
Don Gagne's avatar
Don Gagne committed
468

469 470 471
                QGCLabel {
                    text: qsTr("Entry")
                }
DonLakeFlyer's avatar
DonLakeFlyer committed
472 473 474 475 476 477
                FactComboBox {
                    fact:                   missionItem.gridEntryLocation
                    indexModel:             false
                    Layout.fillWidth:       true
                }

478
                QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
479 480 481 482
                    text:               qsTr("Refly at 90 degree offset")
                    checked:            missionItem.refly90Degrees
                    onClicked:          missionItem.refly90Degrees = checked
                    Layout.columnSpan:  2
483 484
                }

485
                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
486 487
                    wrapMode:               Text.WordWrap
                    text:                   qsTr("Select one:")
488
                    Layout.preferredWidth:  parent.width
DonLakeFlyer's avatar
DonLakeFlyer committed
489
                    Layout.columnSpan:      2
490
                }
Don Gagne's avatar
Don Gagne committed
491 492

                QGCRadioButton {
493
                    id:                     fixedAltitudeRadio
494
                    text:                   qsTr("Altitude")
495
                    checked:                !!missionItem.fixedValueIsAltitude.value
496
                    exclusiveGroup:         fixedValueGroup
497
                    onClicked:              missionItem.fixedValueIsAltitude.value = 1
Don Gagne's avatar
Don Gagne committed
498
                }
499

Don Gagne's avatar
Don Gagne committed
500
                FactTextField {
501 502
                    fact:                   missionItem.gridAltitude
                    enabled:                fixedAltitudeRadio.checked
503
                    Layout.fillWidth:       true
504
                }
Don Gagne's avatar
Don Gagne committed
505 506

                QGCRadioButton {
507
                    id:                     fixedGroundResolutionRadio
508
                    text:                   qsTr("Ground res")
509
                    checked:                !missionItem.fixedValueIsAltitude.value
510
                    exclusiveGroup:         fixedValueGroup
511
                    onClicked:              missionItem.fixedValueIsAltitude.value = 0
512 513
                }

Don Gagne's avatar
Don Gagne committed
514
                FactTextField {
515 516
                    fact:                   missionItem.groundResolution
                    enabled:                fixedGroundResolutionRadio.checked
517
                    Layout.fillWidth:       true
Don Gagne's avatar
Don Gagne committed
518 519 520 521 522
                }
            }
        }

        // Manual grid ui
523 524 525 526 527 528
        SectionHeader {
            id:         manualGridHeader
            text:       qsTr("Grid")
            visible:    gridTypeCombo.currentIndex == _gridTypeManual
        }

DonLakeFlyer's avatar
DonLakeFlyer committed
529
        GridLayout {
Don Gagne's avatar
Don Gagne committed
530 531
            anchors.left:   parent.left
            anchors.right:  parent.right
DonLakeFlyer's avatar
DonLakeFlyer committed
532 533 534
            columnSpacing:  _margin
            rowSpacing:     _margin
            columns:        2
535
            visible:        manualGridHeader.visible && manualGridHeader.checked
Don Gagne's avatar
Don Gagne committed
536

DonLakeFlyer's avatar
DonLakeFlyer committed
537 538
            RowLayout {
                spacing: _margin
539 540

                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
541 542
                    id:                 manualAngleText
                    text:               qsTr("Angle")
543 544 545 546 547 548 549 550
                    Layout.fillWidth:  true
                }

                ToolButton {
                    id:                     manualWindRoseButton
                    anchors.verticalCenter: manualAngleText.verticalCenter
                    Layout.columnSpan:      1
                    iconSource:             qgcPal.globalTheme === QGCPalette.Light ? "/res/wind-roseBlack.svg" : "/res/wind-rose.svg"
551
                    visible:                _vehicle.fixedWing
552 553 554

                    onClicked: {
                        var cords = manualWindRoseButton.mapToItem(_root, 0, 0)
555
                        windRosePie.popup(cords.x + manualWindRoseButton.width / 2, cords.y + manualWindRoseButton.height / 2)
556 557
                    }
                }
DonLakeFlyer's avatar
DonLakeFlyer committed
558
            }
559

DonLakeFlyer's avatar
DonLakeFlyer committed
560 561 562 563
            FactTextField {
                id:                 manualGridAngleText
                fact:               missionItem.gridAngle
                Layout.fillWidth:   true
564 565
            }

DonLakeFlyer's avatar
DonLakeFlyer committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
            QGCLabel { text: qsTr("Spacing") }
            FactTextField {
                fact:                   missionItem.gridSpacing
                Layout.fillWidth:       true
            }

            QGCLabel { text: qsTr("Altitude") }
            FactTextField {
                fact:                   missionItem.gridAltitude
                Layout.fillWidth:       true
            }
            QGCLabel { text: qsTr("Turnaround dist") }
            FactTextField {
                fact:                   missionItem.turnaroundDist
                Layout.fillWidth:       true
Don Gagne's avatar
Don Gagne committed
581
            }
582 583
            QGCLabel {
                text: qsTr("Entry")
584
                visible: !windRoseButton.visible
585
            }
DonLakeFlyer's avatar
DonLakeFlyer committed
586
            FactComboBox {
587
                id: gridAngleBox
DonLakeFlyer's avatar
DonLakeFlyer committed
588
                fact:                   missionItem.gridEntryLocation
589
                visible:                !windRoseButton.visible
DonLakeFlyer's avatar
DonLakeFlyer committed
590 591 592 593
                indexModel:             false
                Layout.fillWidth:       true
            }

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
            FactCheckBox {
                text:               qsTr("Hover and capture image")
                fact:               missionItem.hoverAndCapture
                visible:            missionItem.hoverAndCaptureAllowed
                Layout.columnSpan:  2
                onClicked: {
                    if (checked) {
                        missionItem.cameraTriggerInTurnaround.rawValue = false
                    }
                }
            }

            FactCheckBox {
                text:               qsTr("Take images in turnarounds")
                fact:               missionItem.cameraTriggerInTurnaround
609
                enabled:            missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true
610 611
                Layout.columnSpan:  2
            }
Don Gagne's avatar
Don Gagne committed
612

613
            QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
614 615 616 617
                text:               qsTr("Refly at 90 degree offset")
                checked:            missionItem.refly90Degrees
                onClicked:          missionItem.refly90Degrees = checked
                Layout.columnSpan:  2
618 619
            }

620
            FactCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
621 622 623 624
                anchors.left:       parent.left
                text:               qsTr("Relative altitude")
                fact:               missionItem.gridAltitudeRelative
                Layout.columnSpan:  2
Don Gagne's avatar
Don Gagne committed
625
            }
Don Gagne's avatar
Don Gagne committed
626 627
        }

628 629 630
        SectionHeader {
            id:     statsHeader
            text:   qsTr("Statistics") }
631 632

        Grid {
633 634
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
635
            visible:        statsHeader.checked
636

637
            QGCLabel { text: qsTr("Survey area") }
638 639
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

640
            QGCLabel { text: qsTr("Photo count") }
641
            QGCLabel { text: missionItem.cameraShots }
642

643
            QGCLabel { text: qsTr("Photo interval") }
644 645 646 647 648 649 650 651 652
            QGCLabel {
                text: {
                    var timeVal = missionItem.timeBetweenShots
                    if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
                        return qsTr("N/A")
                    }
                    return timeVal.toFixed(1) + " " + qsTr("secs")
                }
            }
653
        }
654
    }
655

656
    QGCColoredImage {
657 658 659 660 661 662
        id:      windRoseArrow
        source:  "/res/wind-rose-arrow.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 5
        height:  width * 1.454
        smooth:  true
663
        color:   qgcPal.colorGrey
664 665 666 667
        transform: Rotation {
            origin.x: windRoseArrow.width / 2
            origin.y: windRoseArrow.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle
668
        }
669 670
        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
671
        z: windRosePie.z + 1
672 673
    }

674
    QGCColoredImage {
675 676 677 678 679 680
        id:      windGuru
        source:  "/res/wind-guru.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 3
        height:  width * 4.28e-1
        smooth:  true
681
        color:   qgcPal.colorGrey
682 683 684 685 686
        transform: Rotation {
            origin.x: windGuru.width / 2
            origin.y: windGuru.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle + 180
        }
687 688 689
        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
690
    }
691

692 693 694 695 696
    Item {
        id:          windRosePie
        height:      2.6*windRoseButton.height
        width:       2.6*windRoseButton.width
        visible:     false
697
        focus:       true
698

699 700
        property string colorCircle: qgcPal.windowShade
        property string colorBackground: qgcPal.colorGrey
701
        property real lineWidth: windRoseButton.width / 3
702
        property real angle: Number(gridAngleText.text)
703 704 705 706 707 708 709 710 711 712 713 714 715 716

        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()

717
                ctx.beginPath()
718 719 720 721 722
                ctx.arc(x, y, (width / 3) - windRosePie.lineWidth / 2, 0, 2*Math.PI, false)
                ctx.lineWidth = windRosePie.lineWidth
                ctx.strokeStyle = windRosePie.colorBackground
                ctx.stroke()

723
                ctx.beginPath()
724 725 726 727 728
                ctx.arc(x, y, (width / 3) - windRosePie.lineWidth / 2, start, end, false)
                ctx.lineWidth = windRosePie.lineWidth
                ctx.strokeStyle = windRosePie.colorCircle
                ctx.stroke()
            }
729 730
        }

731 732 733 734
        onFocusChanged: {
            visible = focus
        }

735 736
        function popup(x, y) {
            if (x !== undefined)
737
                windRosePie.x = x - windRosePie.width / 2
738
            if (y !== undefined)
739
                windRosePie.y = y - windRosePie.height / 2
740

741
            windRosePie.visible = true
742
            windRosePie.focus = true
743
            missionItemEditorListView.interactive = false
744
        }
745 746 747 748 749 750 751

        MouseArea {
            id: mouseArea
            anchors.fill: parent
            acceptedButtons: Qt.LeftButton | Qt.RightButton

            onClicked: {
752
                windRosePie.visible = false
753
                missionItemEditorListView.interactive = true
754
            }
755 756 757 758 759
            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
760
                gridAngleText.text = angle
761
                gridAngleText.editingFinished()
762 763 764 765 766 767 768 769 770
                if(angle > -135 && angle <= -45) {
                    gridAngleBox.activated(2) // or 3
                } else if(angle > -45 && angle <= 45) {
                    gridAngleBox.activated(2) // or 0
                } else if(angle > 45 && angle <= 135) {
                    gridAngleBox.activated(1) // or 0
                } else if(angle > 135 || angle <= -135) {
                    gridAngleBox.activated(1) // or 3
                }
771 772 773
            }
        }
    }
774
}