|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* (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.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
import QtQuick 2.3
|
|
|
|
import QtQuick.Controls 1.2
|
|
|
|
import QtLocation 5.3
|
|
|
|
import QtPositioning 5.3
|
|
|
|
import QtQuick.Dialogs 1.2
|
|
|
|
|
|
|
|
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
|
|
|
|
allowGCSLocationCenter: !userPanned
|
|
|
|
allowVehicleLocationCenter: !_keepVehicleCentered
|
|
|
|
planView: false
|
|
|
|
|
|
|
|
property alias scaleState: mapScale.state
|
|
|
|
|
|
|
|
// The following properties must be set by the consumer
|
|
|
|
property var planMasterController
|
|
|
|
property var guidedActionsController
|
|
|
|
property var flightWidgets
|
|
|
|
property var rightPanelWidth
|
|
|
|
property var qgcView ///< QGCView control which contains this map
|
|
|
|
property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view
|
|
|
|
|
|
|
|
property rect centerViewport: Qt.rect(0, 0, width, height)
|
|
|
|
|
|
|
|
property var _planMasterController: planMasterController
|
|
|
|
property var _missionController: _planMasterController.missionController
|
|
|
|
property var _geoFenceController: _planMasterController.geoFenceController
|
|
|
|
property var _rallyPointController: _planMasterController.rallyPointController
|
|
|
|
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
|
|
|
|
property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
|
|
|
|
property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2)
|
|
|
|
|
|
|
|
property bool _disableVehicleTracking: false
|
|
|
|
property bool _keepVehicleCentered: _mainIsMap ? false : true
|
|
|
|
|
|
|
|
// Track last known map position and zoom from Fly view in settings
|
|
|
|
onZoomLevelChanged: QGroundControl.flightMapZoom = zoomLevel
|
|
|
|
onCenterChanged: QGroundControl.flightMapPosition = center
|
|
|
|
|
|
|
|
// When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires
|
|
|
|
onUserPannedChanged: {
|
|
|
|
if (userPanned) {
|
|
|
|
console.log("user panned")
|
|
|
|
userPanned = false
|
|
|
|
_disableVehicleTracking = true
|
|
|
|
panRecenterTimer.restart()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 toolStripRightEdge = mapFromItem(toolStrip, toolStrip.x, 0).x + toolStrip.width
|
|
|
|
var instrumentsWidth = 0
|
|
|
|
if (QGroundControl.corePlugin.options.instrumentWidget.widgetPosition === CustomInstrumentWidget.POS_TOP_RIGHT) {
|
|
|
|
// Assume standard instruments
|
|
|
|
instrumentsWidth = flightDisplayViewWidgets.getPreferredInstrumentWidth()
|
|
|
|
}
|
|
|
|
var centerViewport = Qt.rect(toolStripRightEdge, 0, width - toolStripRightEdge - instrumentsWidth, height)
|
|
|
|
return !pointInRect(vehiclePoint, centerViewport)
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateMapToVehiclePosition() {
|
|
|
|
// We let FlightMap handle first vehicle position
|
|
|
|
if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
|
|
|
|
if (_keepVehicleCentered) {
|
|
|
|
flightMap.center = _activeVehicleCoordinate
|
|
|
|
} else {
|
|
|
|
if (firstVehiclePositionReceived && recenterNeeded()) {
|
|
|
|
animatedMapRecenter(flightMap.center, _activeVehicleCoordinate)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer {
|
|
|
|
id: panRecenterTimer
|
|
|
|
interval: 10000
|
|
|
|
running: false
|
|
|
|
|
|
|
|
onTriggered: {
|
|
|
|
_disableVehicleTracking = false
|
|
|
|
updateMapToVehiclePosition()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer {
|
|
|
|
interval: 500
|
|
|
|
running: true
|
|
|
|
repeat: true
|
|
|
|
onTriggered: updateMapToVehiclePosition()
|
|
|
|
}
|
|
|
|
|
|
|
|
QGCPalette { id: qgcPal; colorGroupEnabled: true }
|
|
|
|
QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }
|
|
|
|
|
|
|
|
Connections {
|
|
|
|
target: _missionController
|
|
|
|
|
|
|
|
onNewItemsFromVehicle: {
|
|
|
|
var visualItems = _missionController.visualItems
|
|
|
|
if (visualItems && visualItems.count !== 1) {
|
|
|
|
mapFitFunctions.fitMapViewportToMissionItems()
|
|
|
|
firstVehiclePositionReceived = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ExclusiveGroup {
|
|
|
|
id: _mapTypeButtonsExclusiveGroup
|
|
|
|
}
|
|
|
|
|
|
|
|
MapFitFunctions {
|
|
|
|
id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware!
|
|
|
|
map: _flightMap
|
|
|
|
usePlannedHomePosition: false
|
|
|
|
planMasterController: _planMasterController
|
|
|
|
|
|
|
|
property real leftToolWidth: toolStrip.x + toolStrip.width
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add trajectory points to the map
|
|
|
|
MapItemView {
|
|
|
|
model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0
|
|
|
|
|
|
|
|
delegate: MapPolyline {
|
|
|
|
line.width: 3
|
|
|
|
line.color: "red"
|
|
|
|
z: QGroundControl.zOrderTrajectoryLines
|
|
|
|
path: [
|
|
|
|
object.coordinate1,
|
|
|
|
object.coordinate2,
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the vehicles to the map
|
|
|
|
MapItemView {
|
|
|
|
model: QGroundControl.multiVehicleManager.vehicles
|
|
|
|
|
|
|
|
delegate: VehicleMapItem {
|
|
|
|
vehicle: object
|
|
|
|
coordinate: object.coordinate
|
|
|
|
map: flightMap
|
|
|
|
size: _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight
|
|
|
|
z: QGroundControl.zOrderVehicles
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add ADSB vehicles to the map
|
|
|
|
MapItemView {
|
|
|
|
model: _activeVehicle ? _activeVehicle.adsbVehicles : 0
|
|
|
|
|
|
|
|
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
|
|
|
|
|
|
|
|
delegate: VehicleMapItem {
|
|
|
|
coordinate: object.coordinate
|
|
|
|
altitude: object.altitude
|
|
|
|
callsign: object.callsign
|
|
|
|
heading: object.heading
|
|
|
|
map: flightMap
|
|
|
|
z: QGroundControl.zOrderVehicles
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the items associated with each vehicles flight plan to the map
|
|
|
|
Repeater {
|
|
|
|
model: QGroundControl.multiVehicleManager.vehicles
|
|
|
|
|
|
|
|
PlanMapItems {
|
|
|
|
map: flightMap
|
|
|
|
largeMapView: _mainIsMap
|
|
|
|
masterController: masterController
|
|
|
|
isActiveVehicle: _vehicle.active
|
|
|
|
|
|
|
|
property var _vehicle: object
|
|
|
|
|
|
|
|
PlanMasterController {
|
|
|
|
id: masterController
|
|
|
|
Component.onCompleted: startStaticActiveVehicle(object)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow custom builds to add map items
|
|
|
|
CustomMapItems {
|
|
|
|
map: flightMap
|
|
|
|
largeMapView: _mainIsMap
|
|
|
|
}
|
|
|
|
|
|
|
|
GeoFenceMapVisuals {
|
|
|
|
map: flightMap
|
|
|
|
myGeoFenceController: _geoFenceController
|
|
|
|
interactive: false
|
|
|
|
planView: false
|
|
|
|
homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : QtPositioning.coordinate()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rally points on map
|
|
|
|
MapItemView {
|
|
|
|
model: _rallyPointController.points
|
|
|
|
|
|
|
|
delegate: MapQuickItem {
|
|
|
|
id: itemIndicator
|
|
|
|
anchorPoint.x: sourceItem.anchorPointX
|
|
|
|
anchorPoint.y: sourceItem.anchorPointY
|
|
|
|
coordinate: object.coordinate
|
|
|
|
z: QGroundControl.zOrderMapItems
|
|
|
|
|
|
|
|
sourceItem: MissionItemIndexLabel {
|
|
|
|
id: itemIndexLabel
|
|
|
|
label: qsTr("R", "rally point map item label")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Camera trigger points
|
|
|
|
MapItemView {
|
|
|
|
model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0
|
|
|
|
|
|
|
|
delegate: CameraTriggerIndicator {
|
|
|
|
coordinate: object.coordinate
|
|
|
|
z: QGroundControl.zOrderTopMost
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MapQuickItem {
|
|
|
|
id: gotoLocationItem
|
|
|
|
visible: false
|
|
|
|
z: QGroundControl.zOrderMapItems
|
|
|
|
anchorPoint.x: sourceItem.anchorPointX
|
|
|
|
anchorPoint.y: sourceItem.anchorPointY
|
|
|
|
|
|
|
|
sourceItem: MissionItemIndexLabel {
|
|
|
|
checked: true
|
|
|
|
index: -1
|
|
|
|
label: qsTr("Goto here", "Goto here waypoint")
|
|
|
|
}
|
|
|
|
|
|
|
|
function show(coord) {
|
|
|
|
gotoLocationItem.coordinate = coord
|
|
|
|
gotoLocationItem.visible = true
|
|
|
|
}
|
|
|
|
|
|
|
|
function hide() {
|
|
|
|
gotoLocationItem.visible = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QGCMapCircleVisuals {
|
|
|
|
id: orbitMapCircle
|
|
|
|
mapControl: parent
|
|
|
|
mapCircle: _mapCircle
|
|
|
|
visible: false
|
|
|
|
|
|
|
|
property alias center: _mapCircle.center
|
|
|
|
property real radius: defaultRadius
|
|
|
|
|
|
|
|
readonly property real defaultRadius: 30
|
|
|
|
|
|
|
|
function show(coord) {
|
|
|
|
orbitMapCircle.radius = defaultRadius
|
|
|
|
orbitMapCircle.center = coord
|
|
|
|
orbitMapCircle.visible = true
|
|
|
|
}
|
|
|
|
|
|
|
|
function hide() {
|
|
|
|
orbitMapCircle.visible = false
|
|
|
|
}
|
|
|
|
|
|
|
|
Component.onCompleted: guidedActionsController.orbitMapCircle = orbitMapCircle
|
|
|
|
|
|
|
|
QGCMapCircle {
|
|
|
|
id: _mapCircle
|
|
|
|
interactive: true
|
|
|
|
radius.rawValue: orbitMapCircle.radius
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle guided mode clicks
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
|
|
Menu {
|
|
|
|
id: clickMenu
|
|
|
|
|
|
|
|
property var coord
|
|
|
|
|
|
|
|
MenuItem {
|
|
|
|
text: qsTr("Go to location")
|
|
|
|
visible: guidedActionsController.showGotoLocation
|
|
|
|
|
|
|
|
onTriggered: {
|
|
|
|
gotoLocationItem.show(clickMenu.coord)
|
|
|
|
orbitMapCircle.hide()
|
|
|
|
guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MenuItem {
|
|
|
|
text: qsTr("Orbit at location")
|
|
|
|
visible: guidedActionsController.showOrbit
|
|
|
|
|
|
|
|
onTriggered: {
|
|
|
|
orbitMapCircle.show(clickMenu.coord)
|
|
|
|
gotoLocationItem.hide()
|
|
|
|
guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
if (guidedActionsController.guidedUIVisible || (!guidedActionsController.showGotoLocation && !guidedActionsController.showOrbit)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
orbitMapCircle.hide()
|
|
|
|
gotoLocationItem.hide()
|
|
|
|
var clickCoord = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
|
|
|
|
if (guidedActionsController.showGotoLocation && guidedActionsController.showOrbit) {
|
|
|
|
clickMenu.coord = clickCoord
|
|
|
|
clickMenu.popup()
|
|
|
|
} else if (guidedActionsController.showGotoLocation) {
|
|
|
|
gotoLocationItem.show(clickCoord)
|
|
|
|
guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickCoord)
|
|
|
|
} else if (guidedActionsController.showOrbit) {
|
|
|
|
orbitMapCircle.show(clickCoord)
|
|
|
|
guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickCoord)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MapScale {
|
|
|
|
id: mapScale
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.margins: ScreenTools.defaultFontPixelHeight * (0.33)
|
|
|
|
anchors.topMargin: ScreenTools.defaultFontPixelHeight * (0.33) + state === "bottomMode" ? 0 : ScreenTools.toolbarHeight
|
|
|
|
anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33)
|
|
|
|
mapControl: flightMap
|
|
|
|
visible: !ScreenTools.isTinyScreen
|
|
|
|
state: "bottomMode"
|
|
|
|
states: [
|
|
|
|
State {
|
|
|
|
name: "topMode"
|
|
|
|
AnchorChanges {
|
|
|
|
target: mapScale
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.bottom: undefined
|
|
|
|
}
|
|
|
|
},
|
|
|
|
State {
|
|
|
|
name: "bottomMode"
|
|
|
|
AnchorChanges {
|
|
|
|
target: mapScale
|
|
|
|
anchors.top: undefined
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|