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

8
import QGroundControl               1.0
9 10 11 12 13
import QGroundControl.ScreenTools   1.0
import QGroundControl.Vehicle       1.0
import QGroundControl.Controls      1.0
import QGroundControl.FactControls  1.0
import QGroundControl.Palette       1.0
14
import QGroundControl.FlightMap     1.0
15 16 17 18

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

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

28
    property real   _margin:            ScreenTools.defaultFontPixelWidth / 2
29 30 31 32
    property int    _cameraIndex:       1
    property real   _fieldWidth:        ScreenTools.defaultFontPixelWidth * 10.5
    property var    _cameraList:        [ qsTr("Manual Grid (no camera specs)"), qsTr("Custom Camera Grid") ]
    property var    _vehicle:           QGroundControl.multiVehicleManager.activeVehicle ? QGroundControl.multiVehicleManager.activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
33
    property var    _vehicleCameraList: _vehicle ? _vehicle.staticCameraList : []
Don Gagne's avatar
Don Gagne committed
34 35 36 37 38

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

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

    function recalcFromCameraValues() {
70 71 72 73 74
        var focalLength     = missionItem.cameraFocalLength.rawValue
        var sensorWidth     = missionItem.cameraSensorWidth.rawValue
        var sensorHeight    = missionItem.cameraSensorHeight.rawValue
        var imageWidth      = missionItem.cameraResolutionWidth.rawValue
        var imageHeight     = missionItem.cameraResolutionHeight.rawValue
Don Gagne's avatar
Don Gagne committed
75

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

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

Don Gagne's avatar
Don Gagne committed
85 86
        var imageSizeSideGround     //size in side (non flying) direction of the image on the ground
        var imageSizeFrontGround    //size in front (flying) direction of the image on the ground
Don Gagne's avatar
Don Gagne committed
87 88
        var gridSpacing
        var cameraTriggerDistance
89

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

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

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

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

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

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

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

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

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

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

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

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

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

    Connections {
        target: missionItem

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

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

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

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

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

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

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

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

202
        Column {
Don Gagne's avatar
Don Gagne committed
203 204
            anchors.left:   parent.left
            anchors.right:  parent.right
205 206 207 208 209 210 211 212 213 214 215 216 217
            spacing:        _margin
            visible:        cameraHeader.checked

            QGCComboBox {
                id:             gridTypeCombo
                anchors.left:   parent.left
                anchors.right:  parent.right
                model:          _cameraList
                currentIndex:   -1

                onActivated: {
                    if (index == _gridTypeManual) {
                        missionItem.manualGrid.value = true
218
                        missionItem.fixedValueIsAltitude.value = true
219 220 221 222
                    } else if (index == _gridTypeCustomCamera) {
                        missionItem.manualGrid.value = false
                        missionItem.camera.value = gridTypeCombo.textAt(index)
                        missionItem.cameraOrientationFixed = false
223
                        missionItem.cameraMinTriggerInterval = 0
224 225 226 227 228 229 230 231 232 233 234 235
                    } else {
                        missionItem.manualGrid.value = false
                        missionItem.camera.value = gridTypeCombo.textAt(index)
                        _noCameraValueRecalc = true
                        var listIndex = index - _gridTypeCamera
                        missionItem.cameraSensorWidth.rawValue          = _vehicleCameraList[listIndex].sensorWidth
                        missionItem.cameraSensorHeight.rawValue         = _vehicleCameraList[listIndex].sensorHeight
                        missionItem.cameraResolutionWidth.rawValue      = _vehicleCameraList[listIndex].imageWidth
                        missionItem.cameraResolutionHeight.rawValue     = _vehicleCameraList[listIndex].imageHeight
                        missionItem.cameraFocalLength.rawValue          = _vehicleCameraList[listIndex].focalLength
                        missionItem.cameraOrientationLandscape.rawValue = _vehicleCameraList[listIndex].landscape ? 1 : 0
                        missionItem.cameraOrientationFixed              = _vehicleCameraList[listIndex].fixedOrientation
236
                        missionItem.cameraMinTriggerInterval            = _vehicleCameraList[listIndex].minTriggerInterval
237 238 239 240 241 242 243 244 245 246
                        _noCameraValueRecalc = false
                        recalcFromCameraValues()
                    }
                }
            }

            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
247
                visible:        missionItem.manualGrid.value
248

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

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

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

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

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

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

Don Gagne's avatar
Don Gagne committed
301
            Column {
302
                id:             custCameraCol
Don Gagne's avatar
Don Gagne committed
303 304 305
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
                visible:        gridTypeCombo.currentIndex === _gridTypeCustomCamera

                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
                    Item { Layout.fillWidth: true }
                    QGCLabel {
                        Layout.preferredWidth:  _root._fieldWidth
                        text:                   qsTr("Width")
                    }
                    QGCLabel {
                        Layout.preferredWidth:  _root._fieldWidth
                        text:                   qsTr("Height")
                    }
                }
Don Gagne's avatar
Don Gagne committed
322

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

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

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

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

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

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

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

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

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

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

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

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

DonLakeFlyer's avatar
DonLakeFlyer committed
443 444 445 446 447
                    Rectangle {
                        id:         windRoseButton
                        width:      ScreenTools.implicitTextFieldHeight
                        height:     width
                        color:      qgcPal.button
448
                        visible:    _vehicle ? _vehicle.fixedWing : false
DonLakeFlyer's avatar
DonLakeFlyer committed
449 450 451 452 453 454 455

                        QGCColoredImage {
                            anchors.fill:   parent
                            source:         "/res/wind-rose.svg"
                            smooth:         true
                            color:          qgcPal.buttonText
                        }
456

DonLakeFlyer's avatar
DonLakeFlyer committed
457 458 459 460 461 462 463 464
                        QGCMouseArea {
                            fillItem: parent

                            onClicked: {
                                windRosePie.angle = Number(gridAngleText.text)
                                var cords = windRoseButton.mapToItem(_root, 0, 0)
                                windRosePie.popup(cords.x + windRoseButton.width / 2, cords.y + windRoseButton.height / 2)
                            }
465 466 467 468
                        }
                    }
                }

469
                FactTextField {
470
                    id:                 gridAngleText
471 472
                    fact:               missionItem.gridAngle
                    Layout.fillWidth:   true
473 474
                }

475
                QGCLabel { text: qsTr("Turnaround dist") }
476 477
                FactTextField {
                    fact:                   missionItem.turnaroundDist
478
                    Layout.fillWidth:       true
479
                }
Don Gagne's avatar
Don Gagne committed
480

481 482 483
                QGCLabel {
                    text: qsTr("Entry")
                }
DonLakeFlyer's avatar
DonLakeFlyer committed
484 485 486 487 488 489
                FactComboBox {
                    fact:                   missionItem.gridEntryLocation
                    indexModel:             false
                    Layout.fillWidth:       true
                }

490
                QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
491 492 493 494
                    text:               qsTr("Refly at 90 degree offset")
                    checked:            missionItem.refly90Degrees
                    onClicked:          missionItem.refly90Degrees = checked
                    Layout.columnSpan:  2
495 496
                }

497
                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
498 499
                    wrapMode:               Text.WordWrap
                    text:                   qsTr("Select one:")
500
                    Layout.preferredWidth:  parent.width
DonLakeFlyer's avatar
DonLakeFlyer committed
501
                    Layout.columnSpan:      2
502
                }
Don Gagne's avatar
Don Gagne committed
503 504

                QGCRadioButton {
505
                    id:                     fixedAltitudeRadio
506
                    text:                   qsTr("Altitude")
507
                    checked:                !!missionItem.fixedValueIsAltitude.value
508
                    exclusiveGroup:         fixedValueGroup
509
                    onClicked:              missionItem.fixedValueIsAltitude.value = 1
Don Gagne's avatar
Don Gagne committed
510
                }
511

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

                QGCRadioButton {
519
                    id:                     fixedGroundResolutionRadio
520
                    text:                   qsTr("Ground res")
521
                    checked:                !missionItem.fixedValueIsAltitude.value
522
                    exclusiveGroup:         fixedValueGroup
523
                    onClicked:              missionItem.fixedValueIsAltitude.value = 0
524 525
                }

Don Gagne's avatar
Don Gagne committed
526
                FactTextField {
527 528
                    fact:                   missionItem.groundResolution
                    enabled:                fixedGroundResolutionRadio.checked
529
                    Layout.fillWidth:       true
Don Gagne's avatar
Don Gagne committed
530 531 532 533 534
                }
            }
        }

        // Manual grid ui
535 536 537
        SectionHeader {
            id:         manualGridHeader
            text:       qsTr("Grid")
538
            visible:    gridTypeCombo.currentIndex === _gridTypeManual
539 540
        }

DonLakeFlyer's avatar
DonLakeFlyer committed
541
        GridLayout {
Don Gagne's avatar
Don Gagne committed
542 543
            anchors.left:   parent.left
            anchors.right:  parent.right
DonLakeFlyer's avatar
DonLakeFlyer committed
544 545 546
            columnSpacing:  _margin
            rowSpacing:     _margin
            columns:        2
547
            visible:        manualGridHeader.visible && manualGridHeader.checked
Don Gagne's avatar
Don Gagne committed
548

DonLakeFlyer's avatar
DonLakeFlyer committed
549 550
            RowLayout {
                spacing: _margin
551 552

                QGCLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
553 554
                    id:                 manualAngleText
                    text:               qsTr("Angle")
555 556 557
                    Layout.fillWidth:  true
                }

DonLakeFlyer's avatar
DonLakeFlyer committed
558 559 560 561 562
                Rectangle {
                    id:         manualWindRoseButton
                    width:      ScreenTools.implicitTextFieldHeight
                    height:     width
                    color:      qgcPal.button
563
                    visible:    _vehicle ? _vehicle.fixedWing : false
DonLakeFlyer's avatar
DonLakeFlyer committed
564 565 566 567 568 569 570 571 572 573

                    QGCColoredImage {
                        anchors.fill:   parent
                        source:         "/res/wind-rose.svg"
                        smooth:         true
                        color:          qgcPal.buttonText
                    }

                    QGCMouseArea {
                        fillItem: parent
574

DonLakeFlyer's avatar
DonLakeFlyer committed
575 576 577 578 579
                        onClicked: {
                            windRosePie.angle = Number(gridAngleText.text)
                            var cords = manualWindRoseButton.mapToItem(_root, 0, 0)
                            windRosePie.popup(cords.x + manualWindRoseButton.width / 2, cords.y + manualWindRoseButton.height / 2)
                        }
580 581
                    }
                }
DonLakeFlyer's avatar
DonLakeFlyer committed
582
            }
583

DonLakeFlyer's avatar
DonLakeFlyer committed
584 585 586 587
            FactTextField {
                id:                 manualGridAngleText
                fact:               missionItem.gridAngle
                Layout.fillWidth:   true
588 589
            }

DonLakeFlyer's avatar
DonLakeFlyer committed
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
            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
605
            }
606 607
            QGCLabel {
                text: qsTr("Entry")
608
                visible: !windRoseButton.visible
609
            }
DonLakeFlyer's avatar
DonLakeFlyer committed
610
            FactComboBox {
611
                id: gridAngleBox
DonLakeFlyer's avatar
DonLakeFlyer committed
612
                fact:                   missionItem.gridEntryLocation
613
                visible:                !windRoseButton.visible
DonLakeFlyer's avatar
DonLakeFlyer committed
614 615 616 617
                indexModel:             false
                Layout.fillWidth:       true
            }

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
            FactCheckBox {
                text:               qsTr("Hover and capture image")
                fact:               missionItem.hoverAndCapture
                visible:            missionItem.hoverAndCaptureAllowed
                Layout.columnSpan:  2
                onClicked: {
                    if (checked) {
                        missionItem.cameraTriggerInTurnaround.rawValue = false
                    }
                }
            }

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

637
            QGCCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
638 639 640 641
                text:               qsTr("Refly at 90 degree offset")
                checked:            missionItem.refly90Degrees
                onClicked:          missionItem.refly90Degrees = checked
                Layout.columnSpan:  2
642 643
            }

644
            FactCheckBox {
DonLakeFlyer's avatar
DonLakeFlyer committed
645 646 647 648
                anchors.left:       parent.left
                text:               qsTr("Relative altitude")
                fact:               missionItem.gridAltitudeRelative
                Layout.columnSpan:  2
Don Gagne's avatar
Don Gagne committed
649
            }
Don Gagne's avatar
Don Gagne committed
650 651
        }

652 653 654
        SectionHeader {
            id:     statsHeader
            text:   qsTr("Statistics") }
655 656

        Grid {
657 658
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
659
            visible:        statsHeader.checked
660

661
            QGCLabel { text: qsTr("Survey Area") }
662 663
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

664
            QGCLabel { text: qsTr("Photo Count") }
665
            QGCLabel { text: missionItem.cameraShots }
666

667
            QGCLabel { text: qsTr("Photo Interval") }
668 669 670 671 672 673 674 675 676
            QGCLabel {
                text: {
                    var timeVal = missionItem.timeBetweenShots
                    if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
                        return qsTr("N/A")
                    }
                    return timeVal.toFixed(1) + " " + qsTr("secs")
                }
            }
677 678 679

            QGCLabel { text: qsTr("Trigger Distance") }
            QGCLabel { text: missionItem.cameraTriggerDistance.valueString  + " " + QGroundControl.appSettingsDistanceUnitsString }
680
        }
681
    }
682

683
    QGCColoredImage {
684 685 686 687 688 689
        id:      windRoseArrow
        source:  "/res/wind-rose-arrow.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 5
        height:  width * 1.454
        smooth:  true
690
        color:   qgcPal.colorGrey
691 692 693 694
        transform: Rotation {
            origin.x: windRoseArrow.width / 2
            origin.y: windRoseArrow.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle
695
        }
696 697
        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
698
        z: windRosePie.z + 1
699 700
    }

701
    QGCColoredImage {
702 703 704 705 706 707
        id:      windGuru
        source:  "/res/wind-guru.svg"
        visible: windRosePie.visible
        width:   windRosePie.width / 3
        height:  width * 4.28e-1
        smooth:  true
708
        color:   qgcPal.colorGrey
709 710 711 712 713
        transform: Rotation {
            origin.x: windGuru.width / 2
            origin.y: windGuru.height / 2
            axis { x: 0; y: 0; z: 1 } angle: windRosePie.angle + 180
        }
714 715 716
        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
717
    }
718

719 720 721 722 723
    Item {
        id:          windRosePie
        height:      2.6*windRoseButton.height
        width:       2.6*windRoseButton.width
        visible:     false
724
        focus:       true
725

726 727
        property string colorCircle: qgcPal.windowShade
        property string colorBackground: qgcPal.colorGrey
728
        property real lineWidth: windRoseButton.width / 3
729
        property real angle: Number(gridAngleText.text)
730 731 732 733 734 735 736 737 738 739 740 741 742 743

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

744
                ctx.beginPath()
745 746 747 748 749
                ctx.arc(x, y, (width / 3) - windRosePie.lineWidth / 2, 0, 2*Math.PI, false)
                ctx.lineWidth = windRosePie.lineWidth
                ctx.strokeStyle = windRosePie.colorBackground
                ctx.stroke()

750
                ctx.beginPath()
751 752 753 754 755
                ctx.arc(x, y, (width / 3) - windRosePie.lineWidth / 2, start, end, false)
                ctx.lineWidth = windRosePie.lineWidth
                ctx.strokeStyle = windRosePie.colorCircle
                ctx.stroke()
            }
756 757
        }

758 759 760 761
        onFocusChanged: {
            visible = focus
        }

762 763
        function popup(x, y) {
            if (x !== undefined)
764
                windRosePie.x = x - windRosePie.width / 2
765
            if (y !== undefined)
766
                windRosePie.y = y - windRosePie.height / 2
767

768
            windRosePie.visible = true
769
            windRosePie.focus = true
770
            missionItemEditorListView.interactive = false
771
        }
772 773 774 775 776 777 778

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

            onClicked: {
779
                windRosePie.visible = false
780
                missionItemEditorListView.interactive = true
781
            }
782 783 784 785 786
            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
787
                gridAngleText.text = angle
788
                gridAngleText.editingFinished()
789 790 791 792 793 794 795 796 797
                if(angle > -135 && angle <= -45) {
                    gridAngleBox.activated(2) // or 3
                } else if(angle > -45 && angle <= 45) {
                    gridAngleBox.activated(2) // or 0
                } else if(angle > 45 && angle <= 135) {
                    gridAngleBox.activated(1) // or 0
                } else if(angle > 135 || angle <= -135) {
                    gridAngleBox.activated(1) // or 3
                }
798 799 800
            }
        }
    }
801
}