SurveyItemEditor.qml 18.8 KB
Newer Older
1 2
import QtQuick          2.3
import QtQuick.Controls 1.2
Don Gagne's avatar
Don Gagne committed
3
import QtQuick.Dialogs  1.2
4
import QtQuick.Layouts  1.2
5

6
import QGroundControl               1.0
7 8 9 10 11
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
12
import QGroundControl.FlightMap     1.0
13 14 15 16

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

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

26
    property real   _margin:            ScreenTools.defaultFontPixelWidth / 2
27 28 29 30 31
    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
32 33 34 35 36

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

37 38 39
    Component.onCompleted: {
        for (var i=0; i<_vehicle.cameraList.length; i++) {
            _cameraList.push(_vehicle.cameraList[i].name)
Don Gagne's avatar
Don Gagne committed
40
        }
41
        gridTypeCombo.model = _cameraList
42
        if (missionItem.manualGrid.value) {
43 44
            gridTypeCombo.currentIndex = _gridTypeManual
        } else {
45 46 47 48 49 50
            var index = -1
            for (index=0; index<_cameraList.length; index++) {
                if (_cameraList[index] == missionItem.camera.value) {
                    break;
                }
            }
51 52 53
            if (index == -1) {
                gridTypeCombo.currentIndex = _gridTypeManual
            } else {
54
                var listIndex = index - _gridTypeCamera
55
                gridTypeCombo.currentIndex = index
56
                missionItem.cameraOrientationFixed = _vehicleCameraList[listIndex].fixedOrientation
57
            }
Don Gagne's avatar
Don Gagne committed
58 59
        }
    }
Don Gagne's avatar
Don Gagne committed
60 61

    function recalcFromCameraValues() {
62 63 64 65 66
        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
67

68 69 70 71
        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
72 73

        if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || groundResolution <= 0) {
Don Gagne's avatar
Don Gagne committed
74 75 76
            return
        }

Don Gagne's avatar
Don Gagne committed
77 78
        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
79 80
        var gridSpacing
        var cameraTriggerDistance
81

82
        if (missionItem.fixedValueIsAltitude.value) {
83
            groundResolution = (altitude * sensorWidth * 100) / (imageWidth * focalLength)
Don Gagne's avatar
Don Gagne committed
84 85 86
        } else {
            altitude = (imageWidth * groundResolution * focalLength) / (sensorWidth * 100)
        }
87

88
        if (missionItem.cameraOrientationLandscape.value) {
89
            imageSizeSideGround  = (imageWidth  * groundResolution) / 100
Don Gagne's avatar
Don Gagne committed
90
            imageSizeFrontGround = (imageHeight * groundResolution) / 100
Don Gagne's avatar
Don Gagne committed
91
        } else {
92 93
            imageSizeSideGround  = (imageHeight * groundResolution) / 100
            imageSizeFrontGround = (imageWidth  * groundResolution) / 100
Don Gagne's avatar
Don Gagne committed
94 95
        }

96 97 98
        gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 )
        cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 )

99
        if (missionItem.fixedValueIsAltitude.value) {
Don Gagne's avatar
Don Gagne committed
100 101 102 103
            missionItem.groundResolution.rawValue = groundResolution
        } else {
            missionItem.gridAltitude.rawValue = altitude
        }
Don Gagne's avatar
Don Gagne committed
104 105 106 107
        missionItem.gridSpacing.rawValue = gridSpacing
        missionItem.cameraTriggerDistance.rawValue = cameraTriggerDistance
    }

108
    function polygonCaptureStarted() {
Don Gagne's avatar
Don Gagne committed
109
        missionItem.clearPolygon()
110
    }
Don Gagne's avatar
Don Gagne committed
111

112 113 114
    function polygonCaptureFinished(coordinates) {
        for (var i=0; i<coordinates.length; i++) {
            missionItem.addPolygonCoordinate(coordinates[i])
Don Gagne's avatar
Don Gagne committed
115
        }
116
    }
Don Gagne's avatar
Don Gagne committed
117

118 119
    function polygonAdjustVertex(vertexIndex, vertexCoordinate) {
        missionItem.adjustPolygonCoordinate(vertexIndex, vertexCoordinate)
Don Gagne's avatar
Don Gagne committed
120 121
    }

122 123 124
    function polygonAdjustStarted() { }
    function polygonAdjustFinished() { }

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

127 128 129 130 131 132 133 134 135 136
    Connections {
        target: missionItem.camera

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

Don Gagne's avatar
Don Gagne committed
137 138 139 140
    Connections {
        target: missionItem.gridAltitude

        onValueChanged: {
141
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && missionItem.fixedValueIsAltitude.value && !_noCameraValueRecalc) {
142 143 144 145 146 147 148 149 150 151
                recalcFromCameraValues()
            }
        }
    }

    Connections {
        target: missionItem

        onCameraValueChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera && !_noCameraValueRecalc) {
Don Gagne's avatar
Don Gagne committed
152 153 154 155 156
                recalcFromCameraValues()
            }
        }
    }

157 158
    QGCPalette { id: qgcPal; colorGroupEnabled: true }

Don Gagne's avatar
Don Gagne committed
159
    ExclusiveGroup {
Don Gagne's avatar
Don Gagne committed
160 161 162 163 164 165
        id: cameraOrientationGroup

        onCurrentChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
                recalcFromCameraValues()
            }
166
        }
Don Gagne's avatar
Don Gagne committed
167 168
    }

Don Gagne's avatar
Don Gagne committed
169 170
    ExclusiveGroup { id: fixedValueGroup }

171 172 173 174 175
    Column {
        id:                 editorColumn
        anchors.margins:    _margin
        anchors.top:        parent.top
        anchors.left:       parent.left
176
        anchors.right:      parent.right
177 178
        spacing:            _margin

179 180 181 182
        SectionHeader {
            text:       qsTr("Camera")
            showSpacer: false
        }
183

Don Gagne's avatar
Don Gagne committed
184 185 186 187
        QGCComboBox {
            id:             gridTypeCombo
            anchors.left:   parent.left
            anchors.right:  parent.right
188
            model:          _cameraList
Don Gagne's avatar
Don Gagne committed
189 190 191 192
            currentIndex:   -1

            onActivated: {
                if (index == _gridTypeManual) {
193
                    missionItem.manualGrid.value = true
194
                } else if (index == _gridTypeCustomCamera) {
195 196
                    missionItem.manualGrid.value = false
                    missionItem.camera.value = gridTypeCombo.textAt(index)
197
                    missionItem.cameraOrientationFixed = false
Don Gagne's avatar
Don Gagne committed
198
                } else {
199 200
                    missionItem.manualGrid.value = false
                    missionItem.camera.value = gridTypeCombo.textAt(index)
Don Gagne's avatar
Don Gagne committed
201
                    _noCameraValueRecalc = true
202
                    var listIndex = index - _gridTypeCamera
203 204 205 206 207 208 209
                    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
Don Gagne's avatar
Don Gagne committed
210 211
                    _noCameraValueRecalc = false
                    recalcFromCameraValues()
212 213 214 215
                }
            }
        }

Don Gagne's avatar
Don Gagne committed
216 217
        // Camera based grid ui
        Column {
Don Gagne's avatar
Don Gagne committed
218
            anchors.left:   parent.left
Don Gagne's avatar
Don Gagne committed
219 220 221
            anchors.right:  parent.right
            spacing:        _margin
            visible:        gridTypeCombo.currentIndex != _gridTypeManual
Don Gagne's avatar
Don Gagne committed
222

Don Gagne's avatar
Don Gagne committed
223
            Row {
224 225 226
                spacing:                    _margin
                anchors.horizontalCenter:   parent.horizontalCenter
                visible:                    !missionItem.cameraOrientationFixed
227

Don Gagne's avatar
Don Gagne committed
228 229 230
                QGCRadioButton {
                    width:          _editFieldWidth
                    text:           "Landscape"
231
                    checked:        missionItem.cameraOrientationLandscape.value == 1
Don Gagne's avatar
Don Gagne committed
232
                    exclusiveGroup: cameraOrientationGroup
233
                    onClicked:      missionItem.cameraOrientationLandscape.value = 1
Don Gagne's avatar
Don Gagne committed
234
                }
235

Don Gagne's avatar
Don Gagne committed
236 237 238
                QGCRadioButton {
                    id:             cameraOrientationPortrait
                    text:           "Portrait"
239
                    checked:        missionItem.cameraOrientationLandscape.value == 0
Don Gagne's avatar
Don Gagne committed
240
                    exclusiveGroup: cameraOrientationGroup
241
                    onClicked:      missionItem.cameraOrientationLandscape.value = 0
Don Gagne's avatar
Don Gagne committed
242
                }
243 244
            }

Don Gagne's avatar
Don Gagne committed
245
            Column {
246
                id:             custCameraCol
Don Gagne's avatar
Don Gagne committed
247 248 249
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
                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
266

267 268 269 270
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
271
                    QGCLabel { text: qsTr("Sensor"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
272
                    FactTextField {
273
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
274 275 276
                        fact:                   missionItem.cameraSensorWidth
                    }
                    FactTextField {
277
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
278 279
                        fact:                   missionItem.cameraSensorHeight
                    }
280
                }
Don Gagne's avatar
Don Gagne committed
281

282 283 284 285
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
286
                    QGCLabel { text: qsTr("Image"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
287
                    FactTextField {
288
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
289 290 291
                        fact:                   missionItem.cameraResolutionWidth
                    }
                    FactTextField {
292
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
293 294 295 296
                        fact:                   missionItem.cameraResolutionHeight
                    }
                }

297 298 299 300 301
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
                    QGCLabel {
302
                        text:                   qsTr("Focal length")
303 304 305 306 307 308
                        Layout.fillWidth:       true
                    }
                    FactTextField {
                        Layout.preferredWidth:  _root._fieldWidth
                        fact:                   missionItem.cameraFocalLength
                    }
Don Gagne's avatar
Don Gagne committed
309 310
                }

311
            } // Column - custom camera
Don Gagne's avatar
Don Gagne committed
312

313 314 315
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
Don Gagne's avatar
Don Gagne committed
316
                spacing:        _margin
317 318 319 320
                Item { Layout.fillWidth: true }
                QGCLabel {
                    Layout.preferredWidth:  _root._fieldWidth
                    text:                   qsTr("Frontal")
Don Gagne's avatar
Don Gagne committed
321 322
                }
                QGCLabel {
323 324
                    Layout.preferredWidth:  _root._fieldWidth
                    text:                   qsTr("Side")
Don Gagne's avatar
Don Gagne committed
325
                }
326
            }
Don Gagne's avatar
Don Gagne committed
327

328 329 330 331
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
332
                QGCLabel { text: qsTr("Overlap"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
333
                FactTextField {
334 335
                    Layout.preferredWidth:  _root._fieldWidth
                    fact:                   missionItem.frontalOverlap
Don Gagne's avatar
Don Gagne committed
336 337
                }
                FactTextField {
338 339
                    Layout.preferredWidth:  _root._fieldWidth
                    fact:                   missionItem.sideOverlap
Don Gagne's avatar
Don Gagne committed
340
                }
Don Gagne's avatar
Don Gagne committed
341 342
            }

343
            SectionHeader { text: qsTr("Grid") }
Don Gagne's avatar
Don Gagne committed
344

345
            GridLayout {
Don Gagne's avatar
Don Gagne committed
346 347
                anchors.left:   parent.left
                anchors.right:  parent.right
348 349 350 351 352
                columnSpacing:  _margin
                rowSpacing:     _margin
                columns:        2

                QGCLabel { text: qsTr("Angle") }
353
                FactTextField {
354 355
                    fact:               missionItem.gridAngle
                    Layout.fillWidth:   true
356 357
                }

358
                QGCLabel { text: qsTr("Turnaround dist") }
359 360
                FactTextField {
                    fact:                   missionItem.turnaroundDist
361
                    Layout.fillWidth:       true
362
                }
Don Gagne's avatar
Don Gagne committed
363

364 365 366 367 368 369 370
                QGCLabel {
                    wrapMode:       Text.WordWrap
                    font.pointSize: ScreenTools.smallFontPointSize
                    text:           qsTr("Which value would you like to keep constant as you adjust other settings")
                    Layout.preferredWidth:  parent.width
                    Layout.columnSpan: 2
                }
Don Gagne's avatar
Don Gagne committed
371 372

                QGCRadioButton {
373
                    id:                     fixedAltitudeRadio
374
                    text:                   qsTr("Altitude")
375
                    checked:                missionItem.fixedValueIsAltitude.value
376
                    exclusiveGroup:         fixedValueGroup
377
                    onClicked:              missionItem.fixedValueIsAltitude.value = 1
Don Gagne's avatar
Don Gagne committed
378
                }
379

Don Gagne's avatar
Don Gagne committed
380
                FactTextField {
381 382
                    fact:                   missionItem.gridAltitude
                    enabled:                fixedAltitudeRadio.checked
383
                    Layout.fillWidth:       true
384
                }
Don Gagne's avatar
Don Gagne committed
385 386

                QGCRadioButton {
387
                    id:                     fixedGroundResolutionRadio
388
                    text:                   qsTr("Ground res")
389
                    checked:                !missionItem.fixedValueIsAltitude.value
390
                    exclusiveGroup:         fixedValueGroup
391
                    onClicked:              missionItem.fixedValueIsAltitude.value = 0
392 393
                }

Don Gagne's avatar
Don Gagne committed
394
                FactTextField {
395 396
                    fact:                   missionItem.groundResolution
                    enabled:                fixedGroundResolutionRadio.checked
397
                    Layout.fillWidth:       true
Don Gagne's avatar
Don Gagne committed
398 399 400 401 402
                }
            }
        }

        // Manual grid ui
403
        Column {
Don Gagne's avatar
Don Gagne committed
404 405 406 407
            anchors.left:   parent.left
            anchors.right:  parent.right
            spacing:        _margin
            visible:        gridTypeCombo.currentIndex == _gridTypeManual
408

409
            SectionHeader { text: qsTr("Grid") }
Don Gagne's avatar
Don Gagne committed
410

Don Gagne's avatar
Don Gagne committed
411 412 413
            FactTextFieldGrid {
                anchors.left:   parent.left
                anchors.right:  parent.right
414
                columnSpacing:  ScreenTools.defaultFontPixelWidth
Don Gagne's avatar
Don Gagne committed
415 416
                rowSpacing:     _margin
                factList:       [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
417
                factLabels:     [ qsTr("Angle"), qsTr("Spacing"), qsTr("Altitude"), qsTr("Turnaround dist")]
Don Gagne's avatar
Don Gagne committed
418
            }
Don Gagne's avatar
Don Gagne committed
419

420 421
            Item { height: _margin;  width: 1; visible: !ScreenTools.isTinyScreen }

422
            FactCheckBox {
Don Gagne's avatar
Don Gagne committed
423 424
                anchors.left:   parent.left
                text:           qsTr("Relative altitude")
425
                fact:           missionItem.gridAltitudeRelative
Don Gagne's avatar
Don Gagne committed
426
            }
427

428 429
            Item { height: _sectionSpacer;  width: 1; visible: !ScreenTools.isTinyScreen }

430
            QGCLabel { text: qsTr("Camera") }
431

Don Gagne's avatar
Don Gagne committed
432 433 434 435 436
            Rectangle {
                anchors.left:   parent.left
                anchors.right:  parent.right
                height:         1
                color:          qgcPal.text
Don Gagne's avatar
Don Gagne committed
437 438
            }

Don Gagne's avatar
Don Gagne committed
439 440 441 442 443
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin

444
                FactCheckBox {
Don Gagne's avatar
Don Gagne committed
445
                    anchors.baseline:   cameraTriggerDistanceField.baseline
446
                    text:               qsTr("Trigger Distance")
447
                    fact:               missionItem.cameraTrigger
Don Gagne's avatar
Don Gagne committed
448
                }
Don Gagne's avatar
Don Gagne committed
449

Don Gagne's avatar
Don Gagne committed
450 451 452 453
                FactTextField {
                    id:                 cameraTriggerDistanceField
                    Layout.fillWidth:   true
                    fact:               missionItem.cameraTriggerDistance
454
                    enabled:            missionItem.cameraTrigger.value
Don Gagne's avatar
Don Gagne committed
455
                }
Don Gagne's avatar
Don Gagne committed
456 457 458
            }
        }

459
        SectionHeader { text: qsTr("Statistics") }
460 461

        Grid {
462 463
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
464

465
            QGCLabel { text: qsTr("Survey area") }
466 467
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

468
            QGCLabel { text: qsTr("Photo count") }
469
            QGCLabel { text: missionItem.cameraShots }
470

471
            QGCLabel { text: qsTr("Photo interval") }
472 473 474 475 476 477 478 479 480
            QGCLabel {
                text: {
                    var timeVal = missionItem.timeBetweenShots
                    if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
                        return qsTr("N/A")
                    }
                    return timeVal.toFixed(1) + " " + qsTr("secs")
                }
            }
481
        }
482 483
    }
}