FlyViewMap.qml.orig 20.7 KB
Newer Older
1 2
/****************************************************************************
 *
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
9

10 11 12 13 14
import QtQuick                      2.11
import QtQuick.Controls             2.4
import QtLocation                   5.3
import QtPositioning                5.3
import QtQuick.Dialogs              1.2
15 16

import QGroundControl               1.0
17 18 19
import QGroundControl.Airspace      1.0
import QGroundControl.Controllers   1.0
import QGroundControl.Controls      1.0
20 21 22
import QGroundControl.FlightDisplay 1.0
import QGroundControl.FlightMap     1.0
import QGroundControl.Palette       1.0
23
import QGroundControl.ScreenTools   1.0
24 25 26
import QGroundControl.Vehicle       1.0

FlightMap {
27 28
    id:                         _root
    allowGCSLocationCenter:     true
29
    allowVehicleLocationCenter: !_keepVehicleCentered
30
    planView:                   false
31 32 33 34 35 36 37 38 39
    zoomLevel:                  QGroundControl.flightMapZoom
    center:                     QGroundControl.flightMapPosition

    property Item pipState: _pipState
    QGCPipState {
        id:         _pipState
        pipOverlay: _pipOverlay
        isDark:     _isFullWindowItemDark
    }
40

41
    property var    rightPanelWidth
42 43 44
    property var    planMasterController
    property bool   pipMode:                    false   // true: map is shown in a small pip mode
    property var    toolInsets                          // Insets for the center viewport area
45

46
    property var    _activeVehicle:             QGroundControl.multiVehicleManager.activeVehicle
47 48 49
    property var    _planMasterController:      planMasterController
    property var    _geoFenceController:        planMasterController.geoFenceController
    property var    _rallyPointController:      planMasterController.rallyPointController
50
    property var    _activeVehicleCoordinate:   _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
51
    property real   _toolButtonTopMargin:       parent.height - mainWindow.height + (ScreenTools.defaultFontPixelHeight / 2)
Gus Grubba's avatar
Gus Grubba committed
52
    property bool   _airspaceEnabled:           QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false
53 54
    property var    _flyViewSettings:           QGroundControl.settingsManager.flyViewSettings
    property bool   _keepMapCenteredOnVehicle:  _flyViewSettings.keepMapCenteredOnVehicle.rawValue
55

56
    property bool   _disableVehicleTracking:    false
57 58
    property bool   _keepVehicleCentered:       pipMode ? true : false
    property bool   _saveZoomLevelSetting:      true
59

60
    function updateAirspace(reset) {
61
        if(_airspaceEnabled) {
62 63
            var coordinateNW = _root.toCoordinate(Qt.point(0,0), false /* clipToViewPort */)
            var coordinateSE = _root.toCoordinate(Qt.point(width,height), false /* clipToViewPort */)
64
            if(coordinateNW.isValid && coordinateSE.isValid) {
65
                QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset)
66
            }
67
        }
68 69
    }

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    function _adjustMapZoomForPipMode() {
        _saveZoomLevelSetting = false
        if (pipMode) {
            if (QGroundControl.flightMapZoom > 3) {
                zoomLevel = QGroundControl.flightMapZoom - 3
            }
        } else {
            zoomLevel = QGroundControl.flightMapZoom
        }
        _saveZoomLevelSetting = true
    }

    onPipModeChanged: _adjustMapZoomForPipMode()

    onVisibleChanged: {
        if (visible) {
            // Synchronize center position with Plan View
            center = QGroundControl.flightMapPosition
        }
    }
90 91

    onZoomLevelChanged: {
92 93 94 95
        if (_saveZoomLevelSetting) {
            QGroundControl.flightMapZoom = zoomLevel
            updateAirspace(false)
        }
96 97
    }
    onCenterChanged: {
98
        QGroundControl.flightMapPosition = center
99
        updateAirspace(false)
100
    }
101

Gus Grubba's avatar
Gus Grubba committed
102
    on_AirspaceEnabledChanged: {
103
        updateAirspace(true)
Gus Grubba's avatar
Gus Grubba committed
104 105
    }

106 107 108 109 110 111 112 113 114 115
    // We track whether the user has panned or not to correctly handle automatic map positioning
    Connections {
        target: gesture

        onPanStarted:       _disableVehicleTracking = true
        onFlickStarted:     _disableVehicleTracking = true
        onPanFinished:      panRecenterTimer.restart()
        onFlickFinished:    panRecenterTimer.restart()
    }

116 117 118 119 120 121 122 123 124 125 126 127 128 129
    function pointInRect(point, rect) {
        return point.x > rect.x &&
                point.x < rect.x + rect.width &&
                point.y > rect.y &&
                point.y < rect.y + rect.height;
    }

    property real _animatedLatitudeStart
    property real _animatedLatitudeStop
    property real _animatedLongitudeStart
    property real _animatedLongitudeStop
    property real animatedLatitude
    property real animatedLongitude

130 131
    onAnimatedLatitudeChanged: _root.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude)
    onAnimatedLongitudeChanged: _root.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude)
132 133 134 135 136 137 138 139 140 141 142 143 144

    NumberAnimation on animatedLatitude { id: animateLat; from: _animatedLatitudeStart; to: _animatedLatitudeStop; duration: 1000 }
    NumberAnimation on animatedLongitude { id: animateLong; from: _animatedLongitudeStart; to: _animatedLongitudeStop; duration: 1000 }

    function animatedMapRecenter(fromCoord, toCoord) {
        _animatedLatitudeStart = fromCoord.latitude
        _animatedLongitudeStart = fromCoord.longitude
        _animatedLatitudeStop = toCoord.latitude
        _animatedLongitudeStop = toCoord.longitude
        animateLat.start()
        animateLong.start()
    }

145 146 147 148 149 150 151
    function _insetRect() {
        return Qt.rect(toolInsets.leftEdgeCenterInset,
                       toolInsets.topEdgeCenterInset,
                       _root.width - toolInsets.leftEdgeCenterInset - toolInsets.rightEdgeCenterInset,
                       _root.height - toolInsets.topEdgeCenterInset - toolInsets.bottomEdgeCenterInset)
    }

152
    function recenterNeeded() {
153 154 155
        var vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
        var insetRect = _insetRect()
        return !pointInRect(vehiclePoint, insetRect)
156 157 158
    }

    function updateMapToVehiclePosition() {
159 160 161
        if (animateLat.running || animateLong.running) {
            return
        }
162
        // We let FlightMap handle first vehicle position
163
        if (!_keepMapCenteredOnVehicle && firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
164
            if (_keepVehicleCentered) {
165
                _root.center = _activeVehicleCoordinate
166
            } else {
DonLakeFlyer's avatar
DonLakeFlyer committed
167
                if (firstVehiclePositionReceived && recenterNeeded()) {
168 169 170 171 172 173 174 175
                    // Move the map such that the vehicle is centered within the inset area
                    var vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
                    var insetRect = _insetRect()
                    var centerInsetPoint = Qt.point(insetRect.x + insetRect.width / 2, insetRect.y + insetRect.height / 2)
                    var centerOffset = Qt.point((_root.width / 2) - centerInsetPoint.x, (_root.height / 2) - centerInsetPoint.y)
                    var vehicleOffsetPoint = Qt.point(vehiclePoint.x + centerOffset.x, vehiclePoint.y + centerOffset.y)
                    var vehicleOffsetCoord = _root.toCoordinate(vehicleOffsetPoint, false /* clipToViewport */)
                    animatedMapRecenter(_root.center, vehicleOffsetCoord)
176 177
                }
            }
178 179 180
        }
    }

181 182 183 184 185 186
    on_ActiveVehicleCoordinateChanged: {
        if (_keepMapCenteredOnVehicle && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
            _root.center = _activeVehicleCoordinate
        }
    }

187
    Timer {
188 189 190
        id:         panRecenterTimer
        interval:   10000
        running:    false
191
        onTriggered: {
192
            _disableVehicleTracking = false
193
            updateMapToVehiclePosition()
194 195 196
        }
    }

197 198 199 200 201 202 203
    Timer {
        interval:       500
        running:        true
        repeat:         true
        onTriggered:    updateMapToVehiclePosition()
    }

204
    QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }
Don Gagne's avatar
Don Gagne committed
205

206
    Connections {
207 208
        target:                 _missionController
        ignoreUnknownSignals:   true
209
        onNewItemsFromVehicle: {
210
            var visualItems = _missionController.visualItems
211
            if (visualItems && visualItems.count !== 1) {
212
                mapFitFunctions.fitMapViewportToMissionItems()
213
                firstVehiclePositionReceived = true
214 215
            }
        }
216 217
    }

Don Gagne's avatar
Don Gagne committed
218
    MapFitFunctions {
219
        id:                         mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware!
220
        map:                        _root
Don Gagne's avatar
Don Gagne committed
221
        usePlannedHomePosition:     false
222
        planMasterController:       _planMasterController
223 224
    }

225 226 227 228 229 230 231 232 233 234 235 236
    // Add trajectory lines to the map
    MapPolyline {
        id:         trajectoryPolyline
        line.width: 3
        line.color: "red"
        z:          QGroundControl.zOrderTrajectoryLines
        visible:    !pipMode

        Connections {
            target:                 QGroundControl.multiVehicleManager
            onActiveVehicleChanged: trajectoryPolyline.path = _activeVehicle ? _activeVehicle.trajectoryPoints.list() : []
        }
DonLakeFlyer's avatar
DonLakeFlyer committed
237

238 239 240 241 242
        Connections {
            target:                 _activeVehicle ? _activeVehicle.trajectoryPoints : null
            onPointAdded:           trajectoryPolyline.addCoordinate(coordinate)
            onUpdateLastPoint:      trajectoryPolyline.replaceCoordinate(trajectoryPolyline.pathLength() - 1, coordinate)
            onPointsCleared:        trajectoryPolyline.path = []
Don Gagne's avatar
Don Gagne committed
243
        }
244 245 246 247
    }

    // Add the vehicles to the map
    MapItemView {
248
        model: QGroundControl.multiVehicleManager.vehicles
DonLakeFlyer's avatar
DonLakeFlyer committed
249
        delegate: VehicleMapItem {
Don Gagne's avatar
Don Gagne committed
250 251
            vehicle:        object
            coordinate:     object.coordinate
252 253 254 255 256 257 258 259 260 261 262 263
            map:            _root
            size:           pipMode ? ScreenTools.defaultFontPixelHeight : ScreenTools.defaultFontPixelHeight * 3
            z:              QGroundControl.zOrderVehicles
        }
    }
    // Add distance sensor view
    MapItemView{
        model: QGroundControl.multiVehicleManager.vehicles
        delegate: ProximityRadarMapView {
            vehicle:        object
            coordinate:     object.coordinate
            map:            _root
DonLakeFlyer's avatar
DonLakeFlyer committed
264
            z:              QGroundControl.zOrderVehicles
Don Gagne's avatar
Don Gagne committed
265
        }
266
    }
267 268
    // Add ADSB vehicles to the map
    MapItemView {
269
        model: QGroundControl.adsbVehicleManager.adsbVehicles
270 271 272
        delegate: VehicleMapItem {
            coordinate:     object.coordinate
            altitude:       object.altitude
273
            callsign:       object.callsign
274
            heading:        object.heading
Gus Grubba's avatar
Gus Grubba committed
275
            alert:          object.alert
276
            map:            _root
277 278 279 280
            z:              QGroundControl.zOrderVehicles
        }
    }

281 282 283 284 285
    // Add the items associated with each vehicles flight plan to the map
    Repeater {
        model: QGroundControl.multiVehicleManager.vehicles

        PlanMapItems {
286 287 288 289
            map:                    _root
            largeMapView:           !pipMode
            planMasterController:   _planMasterController
            vehicle:                _vehicle
290 291 292 293 294 295 296 297

            property var _vehicle: object

            PlanMasterController {
                id: masterController
                Component.onCompleted: startStaticActiveVehicle(object)
            }
        }
298 299
    }

300 301 302 303 304 305 306 307 308 309 310
    MapItemView {
        model: pipMode ? undefined : _missionController.directionArrows

        delegate: MapLineArrow {
            fromCoord:      object ? object.coordinate1 : undefined
            toCoord:        object ? object.coordinate2 : undefined
            arrowPosition:  2
            z:              QGroundControl.zOrderWaypointLines
        }
    }

311 312
    // Allow custom builds to add map items
    CustomMapItems {
313 314
        map:            _root
        largeMapView:   !pipMode
315 316
    }

317
    GeoFenceMapVisuals {
318
        map:                    _root
319
        myGeoFenceController:   _geoFenceController
320
        interactive:            false
321
        planView:               false
322
        homePosition:           _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition :  QtPositioning.coordinate()
323 324
    }

325 326
    // Rally points on map
    MapItemView {
327
        model: _rallyPointController.points
328 329 330

        delegate: MapQuickItem {
            id:             itemIndicator
331 332
            anchorPoint.x:  sourceItem.anchorPointX
            anchorPoint.y:  sourceItem.anchorPointY
333 334 335 336 337 338 339 340 341 342
            coordinate:     object.coordinate
            z:              QGroundControl.zOrderMapItems

            sourceItem: MissionItemIndexLabel {
                id:         itemIndexLabel
                label:      qsTr("R", "rally point map item label")
            }
        }
    }

DonLakeFlyer's avatar
DonLakeFlyer committed
343 344 345 346 347 348 349 350 351 352
    // Camera trigger points
    MapItemView {
        model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0

        delegate: CameraTriggerIndicator {
            coordinate:     object.coordinate
            z:              QGroundControl.zOrderTopMost
        }
    }

353
    // GoTo Location visuals
Don Gagne's avatar
Don Gagne committed
354
    MapQuickItem {
355 356
        id:             gotoLocationItem
        visible:        false
Don Gagne's avatar
Don Gagne committed
357
        z:              QGroundControl.zOrderMapItems
358 359
        anchorPoint.x:  sourceItem.anchorPointX
        anchorPoint.y:  sourceItem.anchorPointY
Don Gagne's avatar
Don Gagne committed
360
        sourceItem: MissionItemIndexLabel {
DonLakeFlyer's avatar
DonLakeFlyer committed
361 362
            checked:    true
            index:      -1
363
            label:      qsTr("Go here", "Go to location waypoint")
Don Gagne's avatar
Don Gagne committed
364
        }
365

366 367 368
        property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false

        onInGotoFlightModeChanged: {
369
            if (!inGotoFlightMode && gotoLocationItem.visible) {
370
                // Hide goto indicator when vehicle falls out of guided mode
371
                gotoLocationItem.visible = false
372 373 374
            }
        }

375 376 377 378 379 380
        Connections {
            target: QGroundControl.multiVehicleManager
            onActiveVehicleChanged: {
                if (!activeVehicle) {
                    gotoLocationItem.visible = false
                }
381 382 383
            }
        }

384 385 386 387
        function show(coord) {
            gotoLocationItem.coordinate = coord
            gotoLocationItem.visible = true
        }
388

389 390 391 392
        function hide() {
            gotoLocationItem.visible = false
        }

393 394 395 396 397 398 399 400
        function actionConfirmed() {
            // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it.
        }

        function actionCancelled() {
            hide()
        }
    }
401

402
    // Orbit editing visuals
403
    QGCMapCircleVisuals {
404 405 406 407
        id:             orbitMapCircle
        mapControl:     parent
        mapCircle:      _mapCircle
        visible:        false
408

409 410
        property alias center:              _mapCircle.center
        property alias clockwiseRotation:   _mapCircle.clockwiseRotation
411 412
        readonly property real defaultRadius: 30

413 414 415 416 417 418
        Connections {
            target: QGroundControl.multiVehicleManager
            onActiveVehicleChanged: {
                if (!activeVehicle) {
                    orbitMapCircle.visible = false
                }
419 420 421
            }
        }

422
        function show(coord) {
DonLakeFlyer's avatar
DonLakeFlyer committed
423
            _mapCircle.radius.rawValue = defaultRadius
424 425 426 427 428 429 430 431
            orbitMapCircle.center = coord
            orbitMapCircle.visible = true
        }

        function hide() {
            orbitMapCircle.visible = false
        }

432 433 434 435 436 437 438 439 440
        function actionConfirmed() {
            // Live orbit status is handled by telemetry so we hide here and telemetry will show again.
            hide()
        }

        function actionCancelled() {
            hide()
        }

DonLakeFlyer's avatar
DonLakeFlyer committed
441 442 443 444
        function radius() {
            return _mapCircle.radius.rawValue
        }

445
        Component.onCompleted: globals.guidedControllerFlyView.orbitMapCircle = orbitMapCircle
446 447 448 449

        QGCMapCircle {
            id:                 _mapCircle
            interactive:        true
DonLakeFlyer's avatar
DonLakeFlyer committed
450
            radius.rawValue:    30
451 452
            showRotation:       true
            clockwiseRotation:  true
453 454 455
        }
    }

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
    // ROI Location visuals
    MapQuickItem {
        id:             roiLocationItem
        visible:        _activeVehicle && _activeVehicle.isROIEnabled
        z:              QGroundControl.zOrderMapItems
        anchorPoint.x:  sourceItem.anchorPointX
        anchorPoint.y:  sourceItem.anchorPointY
        sourceItem: MissionItemIndexLabel {
            checked:    true
            index:      -1
            label:      qsTr("ROI here", "Make this a Region Of Interest")
        }

        //-- Visibilty controlled by actual state
        function show(coord) {
            roiLocationItem.coordinate = coord
        }

        function hide() {
        }

        function actionConfirmed() {
        }

        function actionCancelled() {
        }
    }

484
    // Orbit telemetry visuals
485
    QGCMapCircleVisuals {
486
        id:             orbitTelemetryCircle
487
        mapControl:     parent
Gus Grubba's avatar
Gus Grubba committed
488
        mapCircle:      _activeVehicle ? _activeVehicle.orbitMapCircle : null
489 490 491
        visible:        _activeVehicle ? _activeVehicle.orbitActive : false
    }

492 493 494 495
    MapQuickItem {
        id:             orbitCenterIndicator
        anchorPoint.x:  sourceItem.anchorPointX
        anchorPoint.y:  sourceItem.anchorPointY
Don Gagne's avatar
Don Gagne committed
496
        coordinate:     _activeVehicle ? _activeVehicle.orbitMapCircle.center : QtPositioning.coordinate()
497 498 499 500 501 502 503 504 505
        visible:        orbitTelemetryCircle.visible

        sourceItem: MissionItemIndexLabel {
            checked:    true
            index:      -1
            label:      qsTr("Orbit", "Orbit waypoint")
        }
    }

Don Gagne's avatar
Don Gagne committed
506
    // Handle guided mode clicks
507 508
    MouseArea {
        anchors.fill: parent
Don Gagne's avatar
Don Gagne committed
509

510
        QGCMenu {
DonLakeFlyer's avatar
DonLakeFlyer committed
511
            id: clickMenu
512
            property var coord
513
            QGCMenuItem {
DonLakeFlyer's avatar
DonLakeFlyer committed
514
                text:           qsTr("Go to location")
515
                visible:        globals.guidedControllerFlyView.showGotoLocation
DonLakeFlyer's avatar
DonLakeFlyer committed
516 517

                onTriggered: {
518
                    gotoLocationItem.show(clickMenu.coord)
519
                    globals.guidedControllerFlyView.confirmAction(globals.guidedControllerFlyView.actionGoto, clickMenu.coord, gotoLocationItem)
DonLakeFlyer's avatar
DonLakeFlyer committed
520 521
                }
            }
522
            QGCMenuItem {
DonLakeFlyer's avatar
DonLakeFlyer committed
523
                text:           qsTr("Orbit at location")
524
                visible:        globals.guidedControllerFlyView.showOrbit
525

DonLakeFlyer's avatar
DonLakeFlyer committed
526
                onTriggered: {
527
                    orbitMapCircle.show(clickMenu.coord)
528 529 530 531 532 533 534 535 536 537
                    globals.guidedControllerFlyView.confirmAction(globals.guidedControllerFlyView.actionOrbit, clickMenu.coord, orbitMapCircle)
                }
            }
            QGCMenuItem {
                text:           qsTr("ROI at location")
                visible:        globals.guidedControllerFlyView.showROI

                onTriggered: {
                    roiLocationItem.show(clickMenu.coord)
                    globals.guidedControllerFlyView.confirmAction(globals.guidedControllerFlyView.actionROI, clickMenu.coord, roiLocationItem)
DonLakeFlyer's avatar
DonLakeFlyer committed
538 539 540 541
                }
            }
        }

Don Gagne's avatar
Don Gagne committed
542
        onClicked: {
543 544 545 546
            if (!globals.guidedControllerFlyView.guidedUIVisible && (globals.guidedControllerFlyView.showGotoLocation || globals.guidedControllerFlyView.showOrbit || globals.guidedControllerFlyView.showROI)) {
                orbitMapCircle.hide()
                gotoLocationItem.hide()
                var clickCoord = _root.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
547
                clickMenu.coord = clickCoord
DonLakeFlyer's avatar
DonLakeFlyer committed
548
                clickMenu.popup()
Don Gagne's avatar
Don Gagne committed
549 550
            }
        }
551
    }
552

553
    // Airspace overlap support
554
    MapItemView {
555
        model:              _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : []
556 557 558
        delegate: MapCircle {
            center:         object.center
            radius:         object.radius
559
            color:          object.color
Gus Grubba's avatar
Gus Grubba committed
560 561
            border.color:   object.lineColor
            border.width:   object.lineWidth
562 563 564 565
        }
    }

    MapItemView {
566
        model:              _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : []
567 568
        delegate: MapPolygon {
            path:           object.polygon
569
            color:          object.color
Gus Grubba's avatar
Gus Grubba committed
570 571
            border.color:   object.lineColor
            border.width:   object.lineWidth
572 573
        }
    }
574

575
}