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) {
Don Gagne's avatar
Don Gagne committed
142 143 144 145 146
                recalcFromCameraValues()
            }
        }
    }

147 148
    QGCPalette { id: qgcPal; colorGroupEnabled: true }

Don Gagne's avatar
Don Gagne committed
149
    ExclusiveGroup {
Don Gagne's avatar
Don Gagne committed
150 151 152 153 154 155
        id: cameraOrientationGroup

        onCurrentChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
                recalcFromCameraValues()
            }
156
        }
Don Gagne's avatar
Don Gagne committed
157 158
    }

Don Gagne's avatar
Don Gagne committed
159 160
    ExclusiveGroup { id: fixedValueGroup }

161 162 163 164 165
    Column {
        id:                 editorColumn
        anchors.margins:    _margin
        anchors.top:        parent.top
        anchors.left:       parent.left
166
        anchors.right:      parent.right
167 168
        spacing:            _margin

169 170
        SectionHeader { text: qsTr("Camera") }

Don Gagne's avatar
Don Gagne committed
171 172 173 174
        QGCComboBox {
            id:             gridTypeCombo
            anchors.left:   parent.left
            anchors.right:  parent.right
175
            model:          _cameraList
Don Gagne's avatar
Don Gagne committed
176 177 178 179
            currentIndex:   -1

            onActivated: {
                if (index == _gridTypeManual) {
180
                    missionItem.manualGrid.value = true
181
                } else if (index == _gridTypeCustomCamera) {
182 183
                    missionItem.manualGrid.value = false
                    missionItem.camera.value = gridTypeCombo.textAt(index)
184
                    missionItem.cameraOrientationFixed = false
Don Gagne's avatar
Don Gagne committed
185
                } else {
186 187
                    missionItem.manualGrid.value = false
                    missionItem.camera.value = gridTypeCombo.textAt(index)
Don Gagne's avatar
Don Gagne committed
188
                    _noCameraValueRecalc = true
189
                    var listIndex = index - _gridTypeCamera
190 191 192 193 194 195 196
                    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
197 198
                    _noCameraValueRecalc = false
                    recalcFromCameraValues()
199 200 201 202
                }
            }
        }

Don Gagne's avatar
Don Gagne committed
203 204
        // Camera based grid ui
        Column {
Don Gagne's avatar
Don Gagne committed
205
            anchors.left:   parent.left
Don Gagne's avatar
Don Gagne committed
206 207 208
            anchors.right:  parent.right
            spacing:        _margin
            visible:        gridTypeCombo.currentIndex != _gridTypeManual
Don Gagne's avatar
Don Gagne committed
209

Don Gagne's avatar
Don Gagne committed
210
            Row {
211 212 213
                spacing:                    _margin
                anchors.horizontalCenter:   parent.horizontalCenter
                visible:                    !missionItem.cameraOrientationFixed
214

Don Gagne's avatar
Don Gagne committed
215 216 217
                QGCRadioButton {
                    width:          _editFieldWidth
                    text:           "Landscape"
218
                    checked:        missionItem.cameraOrientationLandscape.value == 1
Don Gagne's avatar
Don Gagne committed
219
                    exclusiveGroup: cameraOrientationGroup
220
                    onClicked:      missionItem.cameraOrientationLandscape.value = 1
Don Gagne's avatar
Don Gagne committed
221
                }
222

Don Gagne's avatar
Don Gagne committed
223 224 225
                QGCRadioButton {
                    id:             cameraOrientationPortrait
                    text:           "Portrait"
226
                    checked:        missionItem.cameraOrientationLandscape.value == 0
Don Gagne's avatar
Don Gagne committed
227
                    exclusiveGroup: cameraOrientationGroup
228
                    onClicked:      missionItem.cameraOrientationLandscape.value = 0
Don Gagne's avatar
Don Gagne committed
229
                }
230 231
            }

Don Gagne's avatar
Don Gagne committed
232
            Column {
233
                id:             custCameraCol
Don Gagne's avatar
Don Gagne committed
234 235 236
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
                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
253

254 255 256 257
                RowLayout {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        _margin
258
                    QGCLabel { text: qsTr("Sensor"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
259
                    FactTextField {
260
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
261 262 263
                        fact:                   missionItem.cameraSensorWidth
                    }
                    FactTextField {
264
                        Layout.preferredWidth:  _root._fieldWidth
Don Gagne's avatar
Don Gagne committed
265 266
                        fact:                   missionItem.cameraSensorHeight
                    }
267
                }
Don Gagne's avatar
Don Gagne committed
268

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

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

298
            } // Column - custom camera
Don Gagne's avatar
Don Gagne committed
299

300 301 302
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
Don Gagne's avatar
Don Gagne committed
303
                spacing:        _margin
304 305 306 307
                Item { Layout.fillWidth: true }
                QGCLabel {
                    Layout.preferredWidth:  _root._fieldWidth
                    text:                   qsTr("Frontal")
Don Gagne's avatar
Don Gagne committed
308 309
                }
                QGCLabel {
310 311
                    Layout.preferredWidth:  _root._fieldWidth
                    text:                   qsTr("Side")
Don Gagne's avatar
Don Gagne committed
312
                }
313
            }
Don Gagne's avatar
Don Gagne committed
314

315 316 317 318
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin
319
                QGCLabel { text: qsTr("Overlap"); Layout.fillWidth: true }
Don Gagne's avatar
Don Gagne committed
320
                FactTextField {
321 322
                    Layout.preferredWidth:  _root._fieldWidth
                    fact:                   missionItem.frontalOverlap
Don Gagne's avatar
Don Gagne committed
323 324
                }
                FactTextField {
325 326
                    Layout.preferredWidth:  _root._fieldWidth
                    fact:                   missionItem.sideOverlap
Don Gagne's avatar
Don Gagne committed
327
                }
Don Gagne's avatar
Don Gagne committed
328 329
            }

330
            Item { height: _sectionSpacer;  width: 1; visible: !ScreenTools.isTinyScreen }
Don Gagne's avatar
Don Gagne committed
331

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

334
            GridLayout {
Don Gagne's avatar
Don Gagne committed
335 336
                anchors.left:   parent.left
                anchors.right:  parent.right
337 338 339 340 341
                columnSpacing:  _margin
                rowSpacing:     _margin
                columns:        2

                QGCLabel { text: qsTr("Angle") }
342
                FactTextField {
343 344
                    fact:               missionItem.gridAngle
                    Layout.fillWidth:   true
345 346
                }

347
                QGCLabel { text: qsTr("Turnaround dist") }
348 349
                FactTextField {
                    fact:                   missionItem.turnaroundDist
350
                    Layout.fillWidth:       true
351
                }
Don Gagne's avatar
Don Gagne committed
352

353 354 355 356 357 358 359
                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
360 361

                QGCRadioButton {
362
                    id:                     fixedAltitudeRadio
363
                    text:                   qsTr("Altitude")
364
                    checked:                missionItem.fixedValueIsAltitude.value
365
                    exclusiveGroup:         fixedValueGroup
366
                    onClicked:              missionItem.fixedValueIsAltitude.value = 1
Don Gagne's avatar
Don Gagne committed
367
                }
368

Don Gagne's avatar
Don Gagne committed
369
                FactTextField {
370 371
                    fact:                   missionItem.gridAltitude
                    enabled:                fixedAltitudeRadio.checked
372
                    Layout.fillWidth:       true
373
                }
Don Gagne's avatar
Don Gagne committed
374 375

                QGCRadioButton {
376
                    id:                     fixedGroundResolutionRadio
377
                    text:                   qsTr("Ground res")
378
                    checked:                !missionItem.fixedValueIsAltitude.value
379
                    exclusiveGroup:         fixedValueGroup
380
                    onClicked:              missionItem.fixedValueIsAltitude.value = 0
381 382
                }

Don Gagne's avatar
Don Gagne committed
383
                FactTextField {
384 385
                    fact:                   missionItem.groundResolution
                    enabled:                fixedGroundResolutionRadio.checked
386
                    Layout.fillWidth:       true
Don Gagne's avatar
Don Gagne committed
387 388 389 390 391
                }
            }
        }

        // Manual grid ui
392
        Column {
Don Gagne's avatar
Don Gagne committed
393 394 395 396
            anchors.left:   parent.left
            anchors.right:  parent.right
            spacing:        _margin
            visible:        gridTypeCombo.currentIndex == _gridTypeManual
397

398
            Item { height: _sectionSpacer;  width: 1; visible: !ScreenTools.isTinyScreen }
399

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

Don Gagne's avatar
Don Gagne committed
402 403 404
            FactTextFieldGrid {
                anchors.left:   parent.left
                anchors.right:  parent.right
405
                columnSpacing:  ScreenTools.defaultFontPixelWidth
Don Gagne's avatar
Don Gagne committed
406 407
                rowSpacing:     _margin
                factList:       [ missionItem.gridAngle, missionItem.gridSpacing, missionItem.gridAltitude, missionItem.turnaroundDist ]
408
                factLabels:     [ qsTr("Angle"), qsTr("Spacing"), qsTr("Altitude"), qsTr("Turnaround dist")]
Don Gagne's avatar
Don Gagne committed
409
            }
Don Gagne's avatar
Don Gagne committed
410

411 412
            Item { height: _margin;  width: 1; visible: !ScreenTools.isTinyScreen }

413
            FactCheckBox {
Don Gagne's avatar
Don Gagne committed
414 415
                anchors.left:   parent.left
                text:           qsTr("Relative altitude")
416
                fact:           missionItem.gridAltitudeRelative
Don Gagne's avatar
Don Gagne committed
417
            }
418

419 420
            Item { height: _sectionSpacer;  width: 1; visible: !ScreenTools.isTinyScreen }

421
            QGCLabel { text: qsTr("Camera") }
422

Don Gagne's avatar
Don Gagne committed
423 424 425 426 427
            Rectangle {
                anchors.left:   parent.left
                anchors.right:  parent.right
                height:         1
                color:          qgcPal.text
Don Gagne's avatar
Don Gagne committed
428 429
            }

Don Gagne's avatar
Don Gagne committed
430 431 432 433 434
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin

435
                FactCheckBox {
Don Gagne's avatar
Don Gagne committed
436
                    anchors.baseline:   cameraTriggerDistanceField.baseline
437
                    text:               qsTr("Trigger Distance")
438
                    fact:               missionItem.cameraTrigger
Don Gagne's avatar
Don Gagne committed
439
                }
Don Gagne's avatar
Don Gagne committed
440

Don Gagne's avatar
Don Gagne committed
441 442 443 444
                FactTextField {
                    id:                 cameraTriggerDistanceField
                    Layout.fillWidth:   true
                    fact:               missionItem.cameraTriggerDistance
445
                    enabled:            missionItem.cameraTrigger.value
Don Gagne's avatar
Don Gagne committed
446
                }
Don Gagne's avatar
Don Gagne committed
447 448 449
            }
        }

450
        Item { height: _sectionSpacer;  width: 1; visible: !ScreenTools.isTinyScreen }
Don Gagne's avatar
Don Gagne committed
451

452
        SectionHeader { text: qsTr("Statistics") }
453 454

        Grid {
455 456
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
457

458
            QGCLabel { text: qsTr("Survey area") }
459 460
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

461
            QGCLabel { text: qsTr("Photo count") }
462
            QGCLabel { text: missionItem.cameraShots }
463

464
            QGCLabel { text: qsTr("Photo interval") }
465 466 467 468 469 470 471 472 473
            QGCLabel {
                text: {
                    var timeVal = missionItem.timeBetweenShots
                    if(!isFinite(timeVal) || missionItem.cameraShots === 0) {
                        return qsTr("N/A")
                    }
                    return timeVal.toFixed(1) + " " + qsTr("secs")
                }
            }
474
        }
475 476
    }
}