SurveyItemEditor.qml 28.8 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"
DonLakeFlyer's avatar
DonLakeFlyer committed
445
                        visible:                _vehicle.fixedWing
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

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

473
                QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
474 475 476 477
                    text:               qsTr("Refly at 90 degree offset")
                    checked:            missionItem.refly90Degrees
                    onClicked:          missionItem.refly90Degrees = checked
                    Layout.columnSpan:  2
478 479
                }

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

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

Don Gagne's avatar
Don Gagne committed
495
                FactTextField {
496 497
                    fact:                   missionItem.gridAltitude
                    enabled:                fixedAltitudeRadio.checked
498
                    Layout.fillWidth:       true
499
                }
Don Gagne's avatar
Don Gagne committed
500 501

                QGCRadioButton {
502
                    id:                     fixedGroundResolutionRadio
503
                    text:                   qsTr("Ground res")
504
                    checked:                !missionItem.fixedValueIsAltitude.value
505
                    exclusiveGroup:         fixedValueGroup
506
                    onClicked:              missionItem.fixedValueIsAltitude.value = 0
507 508
                }

Don Gagne's avatar
Don Gagne committed
509
                FactTextField {
510 511
                    fact:                   missionItem.groundResolution
                    enabled:                fixedGroundResolutionRadio.checked
512
                    Layout.fillWidth:       true
Don Gagne's avatar
Don Gagne committed
513 514 515 516 517
                }
            }
        }

        // Manual grid ui
518 519 520 521 522 523
        SectionHeader {
            id:         manualGridHeader
            text:       qsTr("Grid")
            visible:    gridTypeCombo.currentIndex == _gridTypeManual
        }

DonLakeFlyer's avatar
DonLakeFlyer committed
524
        GridLayout {
Don Gagne's avatar
Don Gagne committed
525 526
            anchors.left:   parent.left
            anchors.right:  parent.right
DonLakeFlyer's avatar
DonLakeFlyer committed
527 528 529
            columnSpacing:  _margin
            rowSpacing:     _margin
            columns:        2
530
            visible:        manualGridHeader.visible && manualGridHeader.checked
Don Gagne's avatar
Don Gagne committed
531

DonLakeFlyer's avatar
DonLakeFlyer committed
532 533
            RowLayout {
                spacing: _margin
534 535

                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
536 537
                    id:                 manualAngleText
                    text:               qsTr("Angle")
538 539 540 541 542 543 544 545
                    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"
DonLakeFlyer's avatar
DonLakeFlyer committed
546
                    visible:                _vehicle.fixedWing
547 548 549 550 551 552

                    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
553
            }
554

DonLakeFlyer's avatar
DonLakeFlyer committed
555 556 557 558
            FactTextField {
                id:                 manualGridAngleText
                fact:               missionItem.gridAngle
                Layout.fillWidth:   true
559 560
            }

DonLakeFlyer's avatar
DonLakeFlyer committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
            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
576
            }
DonLakeFlyer's avatar
DonLakeFlyer committed
577 578 579 580 581 582 583
            QGCLabel { text: qsTr("Entry") }
            FactComboBox {
                fact:                   missionItem.gridEntryLocation
                indexModel:             false
                Layout.fillWidth:       true
            }

Don Gagne's avatar
Don Gagne committed
584

585
            QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
586 587 588 589
                text:               qsTr("Refly at 90 degree offset")
                checked:            missionItem.refly90Degrees
                onClicked:          missionItem.refly90Degrees = checked
                Layout.columnSpan:  2
590 591
            }

592
            FactCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
593 594 595 596
                anchors.left:       parent.left
                text:               qsTr("Relative altitude")
                fact:               missionItem.gridAltitudeRelative
                Layout.columnSpan:  2
Don Gagne's avatar
Don Gagne committed
597
            }
Don Gagne's avatar
Don Gagne committed
598 599
        }

600 601 602
        SectionHeader {
            id:     statsHeader
            text:   qsTr("Statistics") }
603 604

        Grid {
605 606
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
607
            visible:        statsHeader.checked
608

609
            QGCLabel { text: qsTr("Survey area") }
610 611
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

612
            QGCLabel { text: qsTr("Photo count") }
613
            QGCLabel { text: missionItem.cameraShots }
614

615
            QGCLabel { text: qsTr("Photo interval") }
616 617 618 619 620 621 622 623 624
            QGCLabel {
                text: {
                    var timeVal = missionItem.timeBetweenShots
                    if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
                        return qsTr("N/A")
                    }
                    return timeVal.toFixed(1) + " " + qsTr("secs")
                }
            }
625
        }
626
    }
627

628
    QGCColoredImage {
629 630 631 632 633 634
        id:      windRoseArrow
        source:  "/res/wind-rose-arrow.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 5
        height:  width * 1.454
        smooth:  true
635
        color:   qgcPal.colorGrey
636 637 638 639
        transform: Rotation {
            origin.x: windRoseArrow.width / 2
            origin.y: windRoseArrow.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle
640
        }
641 642
        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
643
        z: windRosePie.z + 1
644 645
    }

646
    QGCColoredImage {
647 648 649 650 651 652
        id:      windGuru
        source:  "/res/wind-guru.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 3
        height:  width * 4.28e-1
        smooth:  true
653
        color:   qgcPal.colorGrey
654 655 656 657 658
        transform: Rotation {
            origin.x: windGuru.width / 2
            origin.y: windGuru.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle + 180
        }
659 660 661
        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
662
    }
663

664 665 666 667 668
    Item {
        id:          windRosePie
        height:      2.6*windRoseButton.height
        width:       2.6*windRoseButton.width
        visible:     false
669
        focus:       true
670

671 672
        property string colorCircle: qgcPal.windowShade
        property string colorBackground: qgcPal.colorGrey
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
        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()
            }
701 702
        }

703 704 705 706
        onFocusChanged: {
            visible = focus
        }

707 708 709 710 711
        function popup(x, y) {
            if (x !== undefined)
                windRosePie.x = x - windRosePie.width / 2;
            if (y !== undefined)
                windRosePie.y = y - windRosePie.height / 2;
712

713
            windRosePie.visible = true;
714
            windRosePie.focus = true
715
        }
716 717 718 719 720 721 722 723

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

            onClicked: {
                windRosePie.visible = false;
724
            }
725 726 727 728 729
            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
730
                gridAngleText.text = - angle
731 732 733 734
                gridAngleText.editingFinished();
            }
        }
    }
735
}