SurveyItemEditor.qml 29 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
            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
217
                        missionItem.fixedValueIsAltitude.value = true
218 219 220 221
                    } else if (index == _gridTypeCustomCamera) {
                        missionItem.manualGrid.value = false
                        missionItem.camera.value = gridTypeCombo.textAt(index)
                        missionItem.cameraOrientationFixed = false
222
                        missionItem.cameraMinTriggerInterval = 0
223 224 225 226 227 228 229 230 231 232 233 234
                    } 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
235
                        missionItem.cameraMinTriggerInterval            = _vehicleCameraList[listIndex].minTriggerInterval
236 237 238 239 240 241 242 243 244 245 246 247
                        _noCameraValueRecalc = false
                        recalcFromCameraValues()
                    }
                }
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
            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
            }

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

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

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

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

                    ToolButton {
                        id:                     windRoseButton
                        anchors.verticalCenter: angleText.verticalCenter
445
                        iconSource:             qgcPal.globalTheme === QGCPalette.Light ? "/res/wind-roseBlack.svg" : "/res/wind-rose.svg"
446 447
                        // Wind Rose is temporarily turned off until bugs are fixed
                        visible:                false//_vehicle.fixedWing
448 449 450

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

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

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

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

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

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

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

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

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

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

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

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

DonLakeFlyer's avatar
DonLakeFlyer committed
534 535
            RowLayout {
                spacing: _margin
536 537

                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
538 539
                    id:                 manualAngleText
                    text:               qsTr("Angle")
540 541 542 543 544 545 546 547
                    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"
548 549
                    // Wind Rose is temporarily turned off until bugs are fixed
                    visible:                false//_vehicle.fixedWing
550 551 552 553 554 555

                    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
556
            }
557

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

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

Don Gagne's avatar
Don Gagne committed
587

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

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

603 604 605
        SectionHeader {
            id:     statsHeader
            text:   qsTr("Statistics") }
606 607

        Grid {
608 609
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
610
            visible:        statsHeader.checked
611

612
            QGCLabel { text: qsTr("Survey area") }
613 614
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

615
            QGCLabel { text: qsTr("Photo count") }
616
            QGCLabel { text: missionItem.cameraShots }
617

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

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

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

667 668 669 670 671
    Item {
        id:          windRosePie
        height:      2.6*windRoseButton.height
        width:       2.6*windRoseButton.width
        visible:     false
672
        focus:       true
673

674 675
        property string colorCircle: qgcPal.windowShade
        property string colorBackground: qgcPal.colorGrey
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 701 702 703
        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()
            }
704 705
        }

706 707 708 709
        onFocusChanged: {
            visible = focus
        }

710 711 712 713 714
        function popup(x, y) {
            if (x !== undefined)
                windRosePie.x = x - windRosePie.width / 2;
            if (y !== undefined)
                windRosePie.y = y - windRosePie.height / 2;
715

716
            windRosePie.visible = true;
717
            windRosePie.focus = true
718
        }
719 720 721 722 723 724 725 726

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

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