SurveyItemEditor.qml 29.2 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 33
    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
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 40 41
    Component.onCompleted: {
        for (var i=0; i<_vehicle.cameraList.length; i++) {
            _cameraList.push(_vehicle.cameraList[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
        }
    }
Don Gagne's avatar
Don Gagne committed
67 68

    function recalcFromCameraValues() {
69 70 71 72 73
        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
74

75 76 77 78
        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
79 80

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Connections {
        target: missionItem

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

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

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

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

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

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

186 187 188 189 190 191 192 193 194
        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
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

365
            } // Column - custom camera
Don Gagne's avatar
Don Gagne committed
366

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

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

397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
            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
                enabled:    !missionItem.hoverAndCapture.rawValue
            }

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

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

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

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

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

                        onClicked: {
                            var cords = windRoseButton.mapToItem(_root, 0, 0)
449
                            windRosePie.popup(cords.x + windRoseButton.width / 2, cords.y + windRoseButton.height / 2);
450 451 452 453
                        }
                    }
                }

454
                FactTextField {
455
                    id:                 gridAngleText
456 457
                    fact:               missionItem.gridAngle
                    Layout.fillWidth:   true
458 459
                }

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

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

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

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

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

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

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

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

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

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

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

                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
540 541
                    id:                 manualAngleText
                    text:               qsTr("Angle")
542 543 544 545 546 547 548 549
                    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"
550
                    visible:                _vehicle.fixedWing && !ScreenTools.isMobile
551 552 553 554 555 556

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

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

DonLakeFlyer's avatar
DonLakeFlyer committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
            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
580
            }
581 582
            QGCLabel {
                text: qsTr("Entry")
583
                visible: !windRoseButton.visible
584
            }
DonLakeFlyer's avatar
DonLakeFlyer committed
585 586
            FactComboBox {
                fact:                   missionItem.gridEntryLocation
587
                visible:                !windRoseButton.visible
DonLakeFlyer's avatar
DonLakeFlyer committed
588 589 590 591
                indexModel:             false
                Layout.fillWidth:       true
            }

Don Gagne's avatar
Don Gagne committed
592

593
            QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
594 595 596 597
                text:               qsTr("Refly at 90 degree offset")
                checked:            missionItem.refly90Degrees
                onClicked:          missionItem.refly90Degrees = checked
                Layout.columnSpan:  2
598 599
            }

600
            FactCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
601 602 603 604
                anchors.left:       parent.left
                text:               qsTr("Relative altitude")
                fact:               missionItem.gridAltitudeRelative
                Layout.columnSpan:  2
Don Gagne's avatar
Don Gagne committed
605
            }
Don Gagne's avatar
Don Gagne committed
606 607
        }

608 609 610
        SectionHeader {
            id:     statsHeader
            text:   qsTr("Statistics") }
611 612

        Grid {
613 614
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
615
            visible:        statsHeader.checked
616

617
            QGCLabel { text: qsTr("Survey area") }
618 619
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

620
            QGCLabel { text: qsTr("Photo count") }
621
            QGCLabel { text: missionItem.cameraShots }
622

623
            QGCLabel { text: qsTr("Photo interval") }
624 625 626 627 628 629 630 631 632
            QGCLabel {
                text: {
                    var timeVal = missionItem.timeBetweenShots
                    if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
                        return qsTr("N/A")
                    }
                    return timeVal.toFixed(1) + " " + qsTr("secs")
                }
            }
633
        }
634
    }
635

636
    QGCColoredImage {
637 638 639 640 641 642
        id:      windRoseArrow
        source:  "/res/wind-rose-arrow.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 5
        height:  width * 1.454
        smooth:  true
643
        color:   qgcPal.colorGrey
644 645 646 647
        transform: Rotation {
            origin.x: windRoseArrow.width / 2
            origin.y: windRoseArrow.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle
648
        }
649 650
        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
651
        z: windRosePie.z + 1
652 653
    }

654
    QGCColoredImage {
655 656 657 658 659 660
        id:      windGuru
        source:  "/res/wind-guru.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 3
        height:  width * 4.28e-1
        smooth:  true
661
        color:   qgcPal.colorGrey
662 663 664 665 666
        transform: Rotation {
            origin.x: windGuru.width / 2
            origin.y: windGuru.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle + 180
        }
667 668 669
        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
670
    }
671

672 673 674 675 676
    Item {
        id:          windRosePie
        height:      2.6*windRoseButton.height
        width:       2.6*windRoseButton.width
        visible:     false
677
        focus:       true
678

679 680
        property string colorCircle: qgcPal.windowShade
        property string colorBackground: qgcPal.colorGrey
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
        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()
            }
709 710
        }

711 712 713 714
        onFocusChanged: {
            visible = focus
        }

715 716 717 718 719
        function popup(x, y) {
            if (x !== undefined)
                windRosePie.x = x - windRosePie.width / 2;
            if (y !== undefined)
                windRosePie.y = y - windRosePie.height / 2;
720

721
            windRosePie.visible = true
722
            windRosePie.focus = true
723
            missionItemEditorListView.interactive = false
724
        }
725 726 727 728 729 730 731 732

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

            onClicked: {
                windRosePie.visible = false;
733
                missionItemEditorListView.interactive = true
734
            }
735 736 737 738 739
            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
740
                gridAngleText.text = angle
741 742 743 744
                gridAngleText.editingFinished();
            }
        }
    }
745
}