FlightDisplayViewMap.qml 13.5 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 27 28 29 30

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 {
    id:             flightMap
    anchors.fill:   parent
    mapName:        _mapName

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

    property var    _activeVehicle:                 QGroundControl.multiVehicleManager.activeVehicle
    property bool   _activeVehicleCoordinateValid:  _activeVehicle ? _activeVehicle.coordinateValid : false
    property var    activeVehicleCoordinate:        _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
    property var    _gotoHereCoordinate:            QtPositioning.coordinate()
40
    property int    _retaskSequence:                0
41
    property real   _toolButtonTopMargin:           parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2)
42 43 44 45 46 47

    property bool   _disableVehicleTracking:        false
    property bool   _keepVehicleCentered:           _mainIsMap ? false : true
    property bool   _followVehicleSetting:          true                                                    ///< User facing setting for follow vehicle
    property bool   _followVehicle:                 _followVehicleSetting && _activeVehicleCoordinateValid  ///< Control map follow vehicle functionality
    property bool   _firstVehiclePosition:          true
48

49 50 51 52
    Component.onCompleted: {
        QGroundControl.flightMapPosition = center
        QGroundControl.flightMapZoom = zoomLevel
    }
53

54
    onZoomLevelChanged: QGroundControl.flightMapZoom = zoomLevel
55

56 57 58 59 60 61 62
    // When the user pans the map we leave things alone until the panRecenterTimer fires
    Connections {
        target: gesture

        onPanFinished: {
            _disableVehicleTracking = true
            panRecenterTimer.start()
63 64
        }

65 66 67 68
        onFlickFinished: {
            _disableVehicleTracking = true
            panRecenterTimer.start()
        }
69 70
    }

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    onCenterChanged: QGroundControl.flightMapPosition = center

    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() {
        var vehiclePoint = flightMap.fromCoordinate(activeVehicleCoordinate, false /* clipToViewport */)
        var centerViewport = Qt.rect(0, 0, width, height)
        return !pointInRect(vehiclePoint, centerViewport)
106 107 108
    }

    function updateMapToVehiclePosition() {
109 110 111 112 113 114 115 116 117 118 119 120
        if (_followVehicle && !_disableVehicleTracking) {
            if (_keepVehicleCentered) {
                _firstVehiclePosition = true
                flightMap.center = activeVehicleCoordinate
            } else {
                if (_firstVehiclePosition) {
                    _firstVehiclePosition = false
                    flightMap.center = activeVehicleCoordinate
                } else if (recenterNeeded()) {
                    animatedMapRecenter(flightMap.center, activeVehicleCoordinate)
                }
            }
121 122 123 124
        }
    }

    Timer {
125 126 127
        id:         panRecenterTimer
        interval:   10000
        running:    false
128 129

        onTriggered: {
130
            _disableVehicleTracking = false
131
            updateMapToVehiclePosition()
132 133 134
        }
    }

135 136 137 138 139 140 141
    Timer {
        interval:       500
        running:        true
        repeat:         true
        onTriggered:    updateMapToVehiclePosition()
    }

Don Gagne's avatar
Don Gagne committed
142
    QGCPalette { id: qgcPal; colorGroupEnabled: true }
143
    QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }
Don Gagne's avatar
Don Gagne committed
144

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

150
    GeoFenceController {
151
        id: geoFenceController
152 153 154
        Component.onCompleted: start(false /* editMode */)
    }

155 156 157 158 159
    RallyPointController {
        id: rallyPointController
        Component.onCompleted: start(false /* editMode */)
    }

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 194 195 196 197 198 199 200 201 202
    // 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()

            }
        }
    }

203
    ExclusiveGroup {
Don Gagne's avatar
Don Gagne committed
204
        id: _mapTypeButtonsExclusiveGroup
205 206
    }

Don Gagne's avatar
Don Gagne committed
207 208 209 210 211 212 213 214 215
    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
216
        buttonVisible:      [ true, _showZoom, _showZoom ]
217
        maxHeight:          (_flightVideo.visible ? _flightVideo.y : parent.height) - toolStrip.y   // Massive reach across hack
Don Gagne's avatar
Don Gagne committed
218

Don Gagne's avatar
Don Gagne committed
219
        property bool _showZoom: !ScreenTools.isMobile
Don Gagne's avatar
Don Gagne committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

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

        onClicked: {
Don Gagne's avatar
Don Gagne committed
238 239 240 241 242 243 244
            switch (index) {
            case 2:
                _flightMap.zoomLevel += 0.5
                break
            case 3:
                _flightMap.zoomLevel -= 0.5
                break
245 246 247 248
            }
        }
    }

Don Gagne's avatar
Don Gagne committed
249
    // Toolstrip drop panel compomnents
Don Gagne's avatar
Don Gagne committed
250

Don Gagne's avatar
Don Gagne committed
251 252 253 254 255 256 257 258
    MapFitFunctions {
        id:                         mapFitFunctions
        map:                        _flightMap
        mapFitViewport:             Qt.rect(leftToolWidth, _toolButtonTopMargin, flightMap.width - leftToolWidth - rightPanelWidth, flightMap.height - _toolButtonTopMargin)
        usePlannedHomePosition:     false
        mapMissionController:      missionController
        mapGeoFenceController:     geoFenceController
        mapRallyPointController:   rallyPointController
259

Don Gagne's avatar
Don Gagne committed
260 261
        property real leftToolWidth:    toolStrip.x + toolStrip.width
    }
262

Don Gagne's avatar
Don Gagne committed
263 264
    Component {
        id: centerMapDropPanel
265

Don Gagne's avatar
Don Gagne committed
266
        CenterMapDropPanel {
267 268 269
            map:                _flightMap
            fitFunctions:       mapFitFunctions
            showFollowVehicle:  true
270
            followVehicle:      _followVehicleSetting
271

272
            onFollowVehicleChanged: _followVehicleSetting = followVehicle
Don Gagne's avatar
Don Gagne committed
273 274
        }
    }
275

276 277
    // Add trajectory points to the map
    MapItemView {
278
        model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0
279 280
        delegate:
            MapPolyline {
Don Gagne's avatar
Don Gagne committed
281 282
            line.width: 3
            line.color: "red"
283
            z:          QGroundControl.zOrderMapItems - 2
Don Gagne's avatar
Don Gagne committed
284
            path: [
285 286
                object.coordinate1,
                object.coordinate2,
Don Gagne's avatar
Don Gagne committed
287 288
            ]
        }
289 290 291 292
    }

    // Add the vehicles to the map
    MapItemView {
293
        model: QGroundControl.multiVehicleManager.vehicles
294 295
        delegate:
            VehicleMapItem {
Don Gagne's avatar
Don Gagne committed
296 297 298
            vehicle:        object
            coordinate:     object.coordinate
            isSatellite:    flightMap.isSatelliteMap
Gus Grubba's avatar
Gus Grubba committed
299
            size:           _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight
300
            z:              QGroundControl.zOrderMapItems - 1
Don Gagne's avatar
Don Gagne committed
301
        }
302 303
    }

304 305
    // Add the mission item visuals to the map
    Repeater {
306
        model: _mainIsMap ? missionController.visualItems : 0
307 308

        delegate: MissionItemMapVisual {
309 310 311 312 313 314
            map:        flightMap

            onClicked: {
                _retaskSequence = object.sequenceNumber
                flightWidgets.guidedModeBar.confirmAction(parent.flightWidgets.guidedModeBar.confirmRetask)
            }
315
        }
316 317 318 319
    }

    // Add lines between waypoints
    MissionLineView {
320
        model: _mainIsMap ? missionController.waypointLines : 0
321 322
    }

323 324 325 326 327
    GeoFenceMapVisuals {
        map:                    flightMap
        myGeoFenceController:   geoFenceController
        interactive:            false
        homePosition:           _activeVehicle && _activeVehicle.homePositionAvailable ? _activeVehicle.homePosition : undefined
328 329
    }

330 331 332 333 334 335
    // Rally points on map
    MapItemView {
        model: rallyPointController.points

        delegate: MapQuickItem {
            id:             itemIndicator
336 337
            anchorPoint.x:  sourceItem.anchorPointX
            anchorPoint.y:  sourceItem.anchorPointY
338 339 340 341 342 343 344 345 346 347
            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
348 349 350
    // GoTo here waypoint
    MapQuickItem {
        coordinate:     _gotoHereCoordinate
Don Gagne's avatar
Don Gagne committed
351
        visible:        _activeVehicle && _activeVehicle.guidedMode && _gotoHereCoordinate.isValid
Don Gagne's avatar
Don Gagne committed
352
        z:              QGroundControl.zOrderMapItems
353 354
        anchorPoint.x:  sourceItem.anchorPointX
        anchorPoint.y:  sourceItem.anchorPointY
Don Gagne's avatar
Don Gagne committed
355 356

        sourceItem: MissionItemIndexLabel {
357 358
            checked: true
            label:   qsTr("G", "Goto here waypoint") // second string is translator's hint.
Don Gagne's avatar
Don Gagne committed
359
        }
360 361 362 363 364 365 366 367 368
    }    

    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
369 370 371
    }

    // Handle guided mode clicks
372 373
    MouseArea {
        anchors.fill: parent
Don Gagne's avatar
Don Gagne committed
374 375

        onClicked: {
Don Gagne's avatar
Don Gagne committed
376
            if (_activeVehicle) {
377
                if (flightWidgets.guidedModeBar.state != "Shown") {
Don Gagne's avatar
Don Gagne committed
378
                    flightWidgets.guidedModeBar.state = "Shown"
379 380
                } else {
                    if (flightWidgets.gotoEnabled) {
DonLakeFlyer's avatar
DonLakeFlyer committed
381
                        _gotoHereCoordinate = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
382 383
                        flightWidgets.guidedModeBar.confirmAction(flightWidgets.guidedModeBar.confirmGoTo)
                    }
Don Gagne's avatar
Don Gagne committed
384
                }
Don Gagne's avatar
Don Gagne committed
385 386
            }
        }
387 388
    }
}