FlightDisplayViewMap.qml 12.9 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 {
DonLakeFlyer's avatar
DonLakeFlyer committed
99
                if (firstVehiclePositionReceived && recenterNeeded()) {
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

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

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

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

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 193
    // 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()

            }
        }
    }

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

Don Gagne's avatar
Don Gagne committed
198 199 200 201 202 203 204 205 206
    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
207
        buttonVisible:      [ true, _showZoom, _showZoom ]
208
        maxHeight:          (_flightVideo.visible ? _flightVideo.y : parent.height) - toolStrip.y   // Massive reach across hack
Don Gagne's avatar
Don Gagne committed
209

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        delegate: MapQuickItem {
            id:             itemIndicator
322 323
            anchorPoint.x:  sourceItem.anchorPointX
            anchorPoint.y:  sourceItem.anchorPointY
324 325 326 327 328 329 330 331 332 333
            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
334 335 336
    // GoTo here waypoint
    MapQuickItem {
        coordinate:     _gotoHereCoordinate
Don Gagne's avatar
Don Gagne committed
337
        visible:        _activeVehicle && _activeVehicle.guidedMode && _gotoHereCoordinate.isValid
Don Gagne's avatar
Don Gagne committed
338
        z:              QGroundControl.zOrderMapItems
339 340
        anchorPoint.x:  sourceItem.anchorPointX
        anchorPoint.y:  sourceItem.anchorPointY
Don Gagne's avatar
Don Gagne committed
341 342

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

    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
355 356 357
    }

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

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