FlightDisplayViewMap.qml 12.8 KB
Newer Older
1 2 3 4 5 6 7 8
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * 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 15
import QtQuick          2.3
import QtQuick.Controls 1.2
import QtLocation       5.3
import QtPositioning    5.3
import QtQuick.Dialogs  1.2
16 17 18 19 20 21 22 23 24 25 26

import QGroundControl               1.0
import QGroundControl.FlightDisplay 1.0
import QGroundControl.FlightMap     1.0
import QGroundControl.ScreenTools   1.0
import QGroundControl.Controls      1.0
import QGroundControl.Palette       1.0
import QGroundControl.Vehicle       1.0
import QGroundControl.Controllers   1.0

FlightMap {
27 28 29 30 31
    id:                         flightMap
    anchors.fill:               parent
    mapName:                    _mapName
    allowGCSLocationCenter:     !userPanned
    allowVehicleLocationCenter: !_keepVehicleCentered
32

33
    property alias  missionController: missionController
Don Gagne's avatar
Don Gagne committed
34
    property var    flightWidgets
35
    property var    rightPanelWidth
36
    property var    qgcView                             ///< QGCView control which contains this map
Don Gagne's avatar
Don Gagne committed
37 38

    property var    _activeVehicle:                 QGroundControl.multiVehicleManager.activeVehicle
39
    property var    _activeVehicleCoordinate:       _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
Don Gagne's avatar
Don Gagne committed
40
    property var    _gotoHereCoordinate:            QtPositioning.coordinate()
41
    property int    _retaskSequence:                0
42
    property real   _toolButtonTopMargin:           parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2)
43 44 45

    property bool   _disableVehicleTracking:        false
    property bool   _keepVehicleCentered:           _mainIsMap ? false : true
46

47

48
    // Track last known map position and zoom from Fly view in settings
49
    onZoomLevelChanged: QGroundControl.flightMapZoom = zoomLevel
50
    onCenterChanged:    QGroundControl.flightMapPosition = center
51

52
    // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires
53 54 55
    onUserPannedChanged: {
        _disableVehicleTracking = true
        panRecenterTimer.start()
56 57
    }

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    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

    onAnimatedLatitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude)
    onAnimatedLongitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude)

    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()
    }

    function recenterNeeded() {
88
        var vehiclePoint = flightMap.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
89 90
        var centerViewport = Qt.rect(0, 0, width, height)
        return !pointInRect(vehiclePoint, centerViewport)
91 92 93
    }

    function updateMapToVehiclePosition() {
94 95
        // We let FlightMap handle first vehicle position
        if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
96
            if (_keepVehicleCentered) {
97
                flightMap.center = _activeVehicleCoordinate
98
            } else {
99
                if (firstVehiclePositionReceived) {
100
                    animatedMapRecenter(flightMap.center, _activeVehicleCoordinate)
101 102
                }
            }
103 104 105 106
        }
    }

    Timer {
107 108 109
        id:         panRecenterTimer
        interval:   10000
        running:    false
110 111

        onTriggered: {
112
            _disableVehicleTracking = false
113
            updateMapToVehiclePosition()
114 115 116
        }
    }

117 118 119 120 121 122 123
    Timer {
        interval:       500
        running:        true
        repeat:         true
        onTriggered:    updateMapToVehiclePosition()
    }

Don Gagne's avatar
Don Gagne committed
124
    QGCPalette { id: qgcPal; colorGroupEnabled: true }
125
    QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }
Don Gagne's avatar
Don Gagne committed
126

127
    MissionController {
128
        id: missionController
129

130
        Component.onCompleted: start(false /* editMode */)
131 132 133 134 135 136 137

        onNewItemsFromVehicle: {
            var visualItem = missionController.visualItems
            if (visualItems && visualItems.count != 1) {
                mapFitFunctions.fitMapViewportToMissionItems()
            }
        }
138 139
    }

140
    GeoFenceController {
141
        id: geoFenceController
142 143 144
        Component.onCompleted: start(false /* editMode */)
    }

145 146 147 148 149
    RallyPointController {
        id: rallyPointController
        Component.onCompleted: start(false /* editMode */)
    }

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    // The following code is used to track vehicle states such that we prompt to remove mission from vehicle when mission completes

    property bool vehicleArmed:                 _activeVehicle ? _activeVehicle.armed : false
    property bool vehicleWasArmed:              false
    property bool vehicleInMissionFlightMode:   _activeVehicle ? (_activeVehicle.flightMode === _activeVehicle.missionFlightMode) : false
    property bool promptForMissionRemove:       false

    onVehicleArmedChanged: {
        if (vehicleArmed) {
            if (!promptForMissionRemove) {
                promptForMissionRemove = vehicleInMissionFlightMode
                vehicleWasArmed = true
            }
        } else {
            if (promptForMissionRemove && (missionController.containsItems || geoFenceController.containsItems || rallyPointController.containsItems)) {
                qgcView.showDialog(removeMissionDialogComponent, qsTr("Flight complete"), showDialogDefaultWidth, StandardButton.No | StandardButton.Yes)
            }
            promptForMissionRemove = false
        }
    }

    onVehicleInMissionFlightModeChanged: {
        if (!promptForMissionRemove && vehicleArmed) {
            promptForMissionRemove = true
        }
    }

    Component {
        id: removeMissionDialogComponent

        QGCViewMessage {
            message: qsTr("Do you want to remove the mission from the vehicle?")

            function accept() {
                missionController.removeAllFromVehicle()
                geoFenceController.removeAllFromVehicle()
                rallyPointController.removeAllFromVehicle()
                hideDialog()

            }
        }
    }

193
    ExclusiveGroup {
Don Gagne's avatar
Don Gagne committed
194
        id: _mapTypeButtonsExclusiveGroup
195 196
    }

Don Gagne's avatar
Don Gagne committed
197 198 199 200 201 202 203 204 205
    ToolStrip {
        id:                 toolStrip
        anchors.leftMargin: ScreenTools.defaultFontPixelWidth
        anchors.left:       parent.left
        anchors.topMargin:  _toolButtonTopMargin
        anchors.top:        parent.top
        color:              qgcPal.window
        title:              qsTr("Fly")
        z:                  QGroundControl.zOrderWidgets
206
        buttonVisible:      [ true, _showZoom, _showZoom ]
207
        maxHeight:          (_flightVideo.visible ? _flightVideo.y : parent.height) - toolStrip.y   // Massive reach across hack
Don Gagne's avatar
Don Gagne committed
208

Don Gagne's avatar
Don Gagne committed
209
        property bool _showZoom: !ScreenTools.isMobile
Don Gagne's avatar
Don Gagne committed
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

        model: [
            {
                name:               "Center",
                iconSource:         "/qmlimages/MapCenter.svg",
                dropPanelComponent: centerMapDropPanel
            },
            {
                name:               "In",
                iconSource:         "/qmlimages/ZoomPlus.svg"
            },
            {
                name:               "Out",
                iconSource:         "/qmlimages/ZoomMinus.svg"
            }
        ]
226 227

        onClicked: {
Don Gagne's avatar
Don Gagne committed
228
            switch (index) {
Donald Gagne's avatar
Donald Gagne committed
229
            case 1:
Don Gagne's avatar
Don Gagne committed
230 231
                _flightMap.zoomLevel += 0.5
                break
Donald Gagne's avatar
Donald Gagne committed
232
            case 2:
Don Gagne's avatar
Don Gagne committed
233 234
                _flightMap.zoomLevel -= 0.5
                break
235 236 237 238
            }
        }
    }

Don Gagne's avatar
Don Gagne committed
239
    // Toolstrip drop panel compomnents
Don Gagne's avatar
Don Gagne committed
240

Don Gagne's avatar
Don Gagne committed
241 242 243 244 245 246 247
    MapFitFunctions {
        id:                         mapFitFunctions
        map:                        _flightMap
        usePlannedHomePosition:     false
        mapMissionController:      missionController
        mapGeoFenceController:     geoFenceController
        mapRallyPointController:   rallyPointController
248

Don Gagne's avatar
Don Gagne committed
249 250
        property real leftToolWidth:    toolStrip.x + toolStrip.width
    }
251

Don Gagne's avatar
Don Gagne committed
252 253
    Component {
        id: centerMapDropPanel
254

Don Gagne's avatar
Don Gagne committed
255
        CenterMapDropPanel {
256 257
            map:                _flightMap
            fitFunctions:       mapFitFunctions
Don Gagne's avatar
Don Gagne committed
258 259
        }
    }
260

261 262
    // Add trajectory points to the map
    MapItemView {
263
        model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0
264 265
        delegate:
            MapPolyline {
Don Gagne's avatar
Don Gagne committed
266 267
            line.width: 3
            line.color: "red"
268
            z:          QGroundControl.zOrderMapItems - 2
Don Gagne's avatar
Don Gagne committed
269
            path: [
270 271
                object.coordinate1,
                object.coordinate2,
Don Gagne's avatar
Don Gagne committed
272 273
            ]
        }
274 275 276 277
    }

    // Add the vehicles to the map
    MapItemView {
278
        model: QGroundControl.multiVehicleManager.vehicles
279 280
        delegate:
            VehicleMapItem {
Don Gagne's avatar
Don Gagne committed
281 282 283
            vehicle:        object
            coordinate:     object.coordinate
            isSatellite:    flightMap.isSatelliteMap
Gus Grubba's avatar
Gus Grubba committed
284
            size:           _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight
285
            z:              QGroundControl.zOrderMapItems - 1
Don Gagne's avatar
Don Gagne committed
286
        }
287 288
    }

289 290
    // Add the mission item visuals to the map
    Repeater {
291
        model: _mainIsMap ? missionController.visualItems : 0
292 293

        delegate: MissionItemMapVisual {
294 295 296 297 298 299
            map:        flightMap

            onClicked: {
                _retaskSequence = object.sequenceNumber
                flightWidgets.guidedModeBar.confirmAction(parent.flightWidgets.guidedModeBar.confirmRetask)
            }
300
        }
301 302 303 304
    }

    // Add lines between waypoints
    MissionLineView {
305
        model: _mainIsMap ? missionController.waypointLines : 0
306 307
    }

308 309 310 311 312
    GeoFenceMapVisuals {
        map:                    flightMap
        myGeoFenceController:   geoFenceController
        interactive:            false
        homePosition:           _activeVehicle && _activeVehicle.homePositionAvailable ? _activeVehicle.homePosition : undefined
313 314
    }

315 316 317 318 319 320
    // Rally points on map
    MapItemView {
        model: rallyPointController.points

        delegate: MapQuickItem {
            id:             itemIndicator
321 322
            anchorPoint.x:  sourceItem.anchorPointX
            anchorPoint.y:  sourceItem.anchorPointY
323 324 325 326 327 328 329 330 331 332
            coordinate:     object.coordinate
            z:              QGroundControl.zOrderMapItems

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

Don Gagne's avatar
Don Gagne committed
333 334 335
    // GoTo here waypoint
    MapQuickItem {
        coordinate:     _gotoHereCoordinate
Don Gagne's avatar
Don Gagne committed
336
        visible:        _activeVehicle && _activeVehicle.guidedMode && _gotoHereCoordinate.isValid
Don Gagne's avatar
Don Gagne committed
337
        z:              QGroundControl.zOrderMapItems
338 339
        anchorPoint.x:  sourceItem.anchorPointX
        anchorPoint.y:  sourceItem.anchorPointY
Don Gagne's avatar
Don Gagne committed
340 341

        sourceItem: MissionItemIndexLabel {
342 343
            checked: true
            label:   qsTr("G", "Goto here waypoint") // second string is translator's hint.
Don Gagne's avatar
Don Gagne committed
344
        }
345 346 347 348 349 350 351 352 353
    }    

    MapScale {
        anchors.bottomMargin:   ScreenTools.defaultFontPixelHeight * (0.66)
        anchors.rightMargin:    ScreenTools.defaultFontPixelHeight * (0.33)
        anchors.bottom:         parent.bottom
        anchors.right:          parent.right
        mapControl:             flightMap
        visible:                !ScreenTools.isTinyScreen
Don Gagne's avatar
Don Gagne committed
354 355 356
    }

    // Handle guided mode clicks
357 358
    MouseArea {
        anchors.fill: parent
Don Gagne's avatar
Don Gagne committed
359 360

        onClicked: {
Don Gagne's avatar
Don Gagne committed
361
            if (_activeVehicle) {
362
                if (flightWidgets.guidedModeBar.state != "Shown") {
Don Gagne's avatar
Don Gagne committed
363
                    flightWidgets.guidedModeBar.state = "Shown"
364 365
                } else {
                    if (flightWidgets.gotoEnabled) {
DonLakeFlyer's avatar
DonLakeFlyer committed
366
                        _gotoHereCoordinate = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
367 368
                        flightWidgets.guidedModeBar.confirmAction(flightWidgets.guidedModeBar.confirmGoTo)
                    }
Don Gagne's avatar
Don Gagne committed
369
                }
Don Gagne's avatar
Don Gagne committed
370 371
            }
        }
372 373
    }
}