SurveyItemEditor.qml 30.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 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
                        visible:                _vehicle.fixedWing
447 448

                        onClicked: {
449
                            windRosePie.angle = Number(gridAngleText.text)
450
                            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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
            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
                enabled:            !missionItem.hoverAndCapture.rawValue
                Layout.columnSpan:  2
            }
Don Gagne's avatar
Don Gagne committed
611

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

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

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

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

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

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

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

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

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

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

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

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

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

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

730 731 732 733
        onFocusChanged: {
            visible = focus
        }

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

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

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

            onClicked: {
751
                windRosePie.visible = false
752
                missionItemEditorListView.interactive = true
753
            }
754 755 756 757 758
            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
759
                gridAngleText.text = angle
760
                gridAngleText.editingFinished()
761 762 763 764 765 766 767 768 769
                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
                }
770 771 772
            }
        }
    }
773
}