SurveyItemEditor.qml 18.6 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 171 172
        SectionHeader {
            text:       qsTr("Camera")
            showSpacer: false
        }
173

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

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

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

Don Gagne's avatar
Don Gagne committed
213
            Row {
214 215 216
                spacing:                    _margin
                anchors.horizontalCenter:   parent.horizontalCenter
                visible:                    !missionItem.cameraOrientationFixed
217

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

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

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

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

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

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

301
            } // Column - custom camera
Don Gagne's avatar
Don Gagne committed
302

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

449
        SectionHeader { text: qsTr("Statistics") }
450 451

        Grid {
452 453
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
454

455
            QGCLabel { text: qsTr("Survey area") }
456 457
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

458
            QGCLabel { text: qsTr("Photo count") }
459
            QGCLabel { text: missionItem.cameraShots }
460

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