SurveyItemEditor.qml 18.9 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
            missionItem.cameraOrientationFixed = false
52 53 54 55
            if (index == -1) {
                gridTypeCombo.currentIndex = _gridTypeManual
            } else {
                gridTypeCombo.currentIndex = index
56 57 58 59
                if (index != 1) {
                    // Specific camera is selected
                    missionItem.cameraOrientationFixed = _vehicleCameraList[index - _gridTypeCamera].fixedOrientation
                }
60
            }
Don Gagne's avatar
Don Gagne committed
61 62
        }
    }
Don Gagne's avatar
Don Gagne committed
63 64

    function recalcFromCameraValues() {
65 66 67 68 69
        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
70

71 72 73 74
        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
75 76

        if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || groundResolution <= 0) {
Don Gagne's avatar
Don Gagne committed
77 78 79
            return
        }

Don Gagne's avatar
Don Gagne committed
80 81
        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
82 83
        var gridSpacing
        var cameraTriggerDistance
84

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

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

99 100 101
        gridSpacing = imageSizeSideGround * ( (100-sideOverlap) / 100 )
        cameraTriggerDistance = imageSizeFrontGround * ( (100-frontalOverlap) / 100 )

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

111
    function polygonCaptureStarted() {
Don Gagne's avatar
Don Gagne committed
112
        missionItem.clearPolygon()
113
    }
Don Gagne's avatar
Don Gagne committed
114

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

121 122
    function polygonAdjustVertex(vertexIndex, vertexCoordinate) {
        missionItem.adjustPolygonCoordinate(vertexIndex, vertexCoordinate)
Don Gagne's avatar
Don Gagne committed
123 124
    }

125 126 127
    function polygonAdjustStarted() { }
    function polygonAdjustFinished() { }

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

130 131 132 133 134 135 136 137 138 139
    Connections {
        target: missionItem.camera

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

Don Gagne's avatar
Don Gagne committed
140 141 142 143
    Connections {
        target: missionItem.gridAltitude

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

    Connections {
        target: missionItem

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

160 161
    QGCPalette { id: qgcPal; colorGroupEnabled: true }

Don Gagne's avatar
Don Gagne committed
162
    ExclusiveGroup {
Don Gagne's avatar
Don Gagne committed
163 164 165 166 167 168
        id: cameraOrientationGroup

        onCurrentChanged: {
            if (gridTypeCombo.currentIndex >= _gridTypeCustomCamera) {
                recalcFromCameraValues()
            }
169
        }
Don Gagne's avatar
Don Gagne committed
170 171
    }

Don Gagne's avatar
Don Gagne committed
172 173
    ExclusiveGroup { id: fixedValueGroup }

174 175 176 177 178
    Column {
        id:                 editorColumn
        anchors.margins:    _margin
        anchors.top:        parent.top
        anchors.left:       parent.left
179
        anchors.right:      parent.right
180 181
        spacing:            _margin

182 183 184 185
        SectionHeader {
            text:       qsTr("Camera")
            showSpacer: false
        }
186

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

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

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

Don Gagne's avatar
Don Gagne committed
226
            Row {
227 228 229
                spacing:                    _margin
                anchors.horizontalCenter:   parent.horizontalCenter
                visible:                    !missionItem.cameraOrientationFixed
230

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

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

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

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

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

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

314
            } // Column - custom camera
Don Gagne's avatar
Don Gagne committed
315

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

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

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

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

                QGCLabel { text: qsTr("Angle") }
356
                FactTextField {
357 358
                    fact:               missionItem.gridAngle
                    Layout.fillWidth:   true
359 360
                }

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

367 368 369 370 371 372 373
                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
374 375

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

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

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

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

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

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

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

423 424
            Item { height: _margin;  width: 1; visible: !ScreenTools.isTinyScreen }

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

431 432
            Item { height: _sectionSpacer;  width: 1; visible: !ScreenTools.isTinyScreen }

433
            QGCLabel { text: qsTr("Camera") }
434

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

Don Gagne's avatar
Don Gagne committed
442 443 444 445 446
            RowLayout {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        _margin

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

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

462
        SectionHeader { text: qsTr("Statistics") }
463 464

        Grid {
465 466
            columns:        2
            columnSpacing:  ScreenTools.defaultFontPixelWidth
467

468
            QGCLabel { text: qsTr("Survey area") }
469 470
            QGCLabel { text: QGroundControl.squareMetersToAppSettingsAreaUnits(missionItem.coveredArea).toFixed(2) + " " + QGroundControl.appSettingsAreaUnitsString }

471
            QGCLabel { text: qsTr("Photo count") }
472
            QGCLabel { text: missionItem.cameraShots }
473

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