地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

566 lines
20 KiB

/****************************************************************************
*
* (c) 2009-2020 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.11
import QtQuick.Controls 2.4
import QtLocation 5.3
import QtPositioning 5.3
import QtQuick.Dialogs 1.2
import QGroundControl 1.0
import QGroundControl.Airspace 1.0
import QGroundControl.Controllers 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FlightDisplay 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Vehicle 1.0
FlightMap {
id: _root
allowGCSLocationCenter: true
allowVehicleLocationCenter: !_keepVehicleCentered
planView: false
zoomLevel: QGroundControl.flightMapZoom
center: QGroundControl.flightMapPosition
property Item pipState: _pipState
QGCPipState {
id: _pipState
pipOverlay: _pipOverlay
isDark: _isFullWindowItemDark
}
property var rightPanelWidth
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
property var _planMasterController: planMasterController
property var _geoFenceController: planMasterController.geoFenceController
property var _rallyPointController: planMasterController.rallyPointController
6 years ago
property var _activeVehicleCoordinate: activeVehicle ? activeVehicle.coordinate : QtPositioning.coordinate()
property real _toolButtonTopMargin: parent.height - mainWindow.height + (ScreenTools.defaultFontPixelHeight / 2)
property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false
property var _flyViewSettings: QGroundControl.settingsManager.flyViewSettings
property bool _keepMapCenteredOnVehicle: _flyViewSettings.keepMapCenteredOnVehicle.rawValue
property bool _disableVehicleTracking: false
property bool _keepVehicleCentered: pipMode ? true : false
property bool _saveZoomLevelSetting: true
function updateAirspace(reset) {
if(_airspaceEnabled) {
var coordinateNW = _root.toCoordinate(Qt.point(0,0), false /* clipToViewPort */)
var coordinateSE = _root.toCoordinate(Qt.point(width,height), false /* clipToViewPort */)
if(coordinateNW.isValid && coordinateSE.isValid) {
QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset)
}
}
}
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
}
}
onZoomLevelChanged: {
if (_saveZoomLevelSetting) {
QGroundControl.flightMapZoom = zoomLevel
updateAirspace(false)
}
}
onCenterChanged: {
QGroundControl.flightMapPosition = center
updateAirspace(false)
}
on_AirspaceEnabledChanged: {
updateAirspace(true)
}
// 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()
}
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: _root.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude)
onAnimatedLongitudeChanged: _root.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 _insetRect() {
return Qt.rect(toolInsets.leftEdgeCenterInset,
toolInsets.topEdgeCenterInset,
_root.width - toolInsets.leftEdgeCenterInset - toolInsets.rightEdgeCenterInset,
_root.height - toolInsets.topEdgeCenterInset - toolInsets.bottomEdgeCenterInset)
}
function recenterNeeded() {
var vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
var insetRect = _insetRect()
return !pointInRect(vehiclePoint, insetRect)
}
function updateMapToVehiclePosition() {
if (animateLat.running || animateLong.running) {
return
}
// We let FlightMap handle first vehicle position
if (!_keepMapCenteredOnVehicle && firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
if (_keepVehicleCentered) {
_root.center = _activeVehicleCoordinate
} else {
if (firstVehiclePositionReceived && recenterNeeded()) {
// 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)
}
}
}
}
on_ActiveVehicleCoordinateChanged: {
if (_keepMapCenteredOnVehicle && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
_root.center = _activeVehicleCoordinate
}
}
Timer {
id: panRecenterTimer
interval: 10000
running: false
onTriggered: {
_disableVehicleTracking = false
updateMapToVehiclePosition()
}
}
Timer {
interval: 500
running: true
repeat: true
onTriggered: updateMapToVehiclePosition()
}
QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }
Connections {
target: _missionController
ignoreUnknownSignals: true
onNewItemsFromVehicle: {
var visualItems = _missionController.visualItems
if (visualItems && visualItems.count !== 1) {
mapFitFunctions.fitMapViewportToMissionItems()
firstVehiclePositionReceived = true
}
}
}
MapFitFunctions {
id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware!
map: _root
usePlannedHomePosition: false
planMasterController: _planMasterController
}
// 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() : []
}
Connections {
target: activeVehicle ? activeVehicle.trajectoryPoints : null
onPointAdded: trajectoryPolyline.addCoordinate(coordinate)
onUpdateLastPoint: trajectoryPolyline.replaceCoordinate(trajectoryPolyline.pathLength() - 1, coordinate)
onPointsCleared: trajectoryPolyline.path = []
}
}
// Add the vehicles to the map
MapItemView {
model: QGroundControl.multiVehicleManager.vehicles
8 years ago
delegate: VehicleMapItem {
vehicle: object
coordinate: object.coordinate
map: _root
size: pipMode ? ScreenTools.defaultFontPixelHeight : ScreenTools.defaultFontPixelHeight * 3
8 years ago
z: QGroundControl.zOrderVehicles
}
}
// Add ADSB vehicles to the map
MapItemView {
model: QGroundControl.adsbVehicleManager.adsbVehicles
delegate: VehicleMapItem {
coordinate: object.coordinate
altitude: object.altitude
callsign: object.callsign
heading: object.heading
alert: object.alert
map: _root
z: QGroundControl.zOrderVehicles
}
}
// Add the items associated with each vehicles flight plan to the map
Repeater {
model: QGroundControl.multiVehicleManager.vehicles
PlanMapItems {
map: _root
largeMapView: !pipMode
planMasterController: _planMasterController
vehicle: _vehicle
property var _vehicle: object
PlanMasterController {
id: masterController
Component.onCompleted: startStaticActiveVehicle(object)
}
}
}
MapItemView {
model: pipMode ? undefined : _missionController.directionArrows
delegate: MapLineArrow {
fromCoord: object ? object.coordinate1 : undefined
toCoord: object ? object.coordinate2 : undefined
arrowPosition: 2
z: QGroundControl.zOrderWaypointLines
}
}
// Allow custom builds to add map items
CustomMapItems {
map: _root
largeMapView: !pipMode
}
GeoFenceMapVisuals {
map: _root
myGeoFenceController: _geoFenceController
interactive: false
planView: false
6 years ago
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 {
6 years ago
model: activeVehicle ? activeVehicle.cameraTriggerPoints : 0
delegate: CameraTriggerIndicator {
coordinate: object.coordinate
z: QGroundControl.zOrderTopMost
}
}
// GoTo Location visuals
MapQuickItem {
id: gotoLocationItem
visible: false
z: QGroundControl.zOrderMapItems
anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
sourceItem: MissionItemIndexLabel {
checked: true
index: -1
label: qsTr("Go here", "Go to location waypoint")
}
6 years ago
property bool inGotoFlightMode: activeVehicle ? activeVehicle.flightMode === activeVehicle.gotoFlightMode : false
onInGotoFlightModeChanged: {
if (!inGotoFlightMode && gotoLocationItem.visible) {
// Hide goto indicator when vehicle falls out of guided mode
gotoLocationItem.visible = false
}
}
6 years ago
Connections {
target: mainWindow
onActiveVehicleChanged: {
if (!activeVehicle) {
gotoLocationItem.visible = false
6 years ago
}
}
}
function show(coord) {
gotoLocationItem.coordinate = coord
gotoLocationItem.visible = true
}
function hide() {
gotoLocationItem.visible = false
}
function actionConfirmed() {
// We leave the indicator visible. The handling for onInGuidedModeChanged will hide it.
}
function actionCancelled() {
hide()
}
}
// Orbit editing visuals
QGCMapCircleVisuals {
id: orbitMapCircle
mapControl: parent
mapCircle: _mapCircle
visible: false
property alias center: _mapCircle.center
property alias clockwiseRotation: _mapCircle.clockwiseRotation
readonly property real defaultRadius: 30
6 years ago
Connections {
target: mainWindow
onActiveVehicleChanged: {
if (!activeVehicle) {
orbitMapCircle.visible = false
6 years ago
}
}
}
function show(coord) {
7 years ago
_mapCircle.radius.rawValue = defaultRadius
orbitMapCircle.center = coord
orbitMapCircle.visible = true
}
function hide() {
orbitMapCircle.visible = false
}
function actionConfirmed() {
// Live orbit status is handled by telemetry so we hide here and telemetry will show again.
hide()
}
function actionCancelled() {
hide()
}
7 years ago
function radius() {
return _mapCircle.radius.rawValue
}
Component.onCompleted: mainWindow.guidedControllerFlyView.orbitMapCircle = orbitMapCircle
QGCMapCircle {
id: _mapCircle
interactive: true
7 years ago
radius.rawValue: 30
showRotation: true
clockwiseRotation: true
}
}
5 years ago
// ROI Location visuals
MapQuickItem {
id: roiLocationItem
visible: activeVehicle && activeVehicle.isROIEnabled
5 years ago
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
5 years ago
function show(coord) {
roiLocationItem.coordinate = coord
}
function hide() {
}
function actionConfirmed() {
}
function actionCancelled() {
}
}
// Orbit telemetry visuals
QGCMapCircleVisuals {
id: orbitTelemetryCircle
mapControl: parent
6 years ago
mapCircle: activeVehicle ? activeVehicle.orbitMapCircle : null
visible: activeVehicle ? activeVehicle.orbitActive : false
}
MapQuickItem {
id: orbitCenterIndicator
anchorPoint.x: sourceItem.anchorPointX
anchorPoint.y: sourceItem.anchorPointY
6 years ago
coordinate: activeVehicle ? activeVehicle.orbitMapCircle.center : QtPositioning.coordinate()
visible: orbitTelemetryCircle.visible
sourceItem: MissionItemIndexLabel {
checked: true
index: -1
label: qsTr("Orbit", "Orbit waypoint")
}
}
// Handle guided mode clicks
MouseArea {
anchors.fill: parent
QGCMenu {
id: clickMenu
property var coord
QGCMenuItem {
text: qsTr("Go to location")
visible: mainWindow.guidedControllerFlyView.showGotoLocation
onTriggered: {
gotoLocationItem.show(clickMenu.coord)
mainWindow.guidedControllerFlyView.confirmAction(mainWindow.guidedControllerFlyView.actionGoto, clickMenu.coord, gotoLocationItem)
}
}
QGCMenuItem {
text: qsTr("Orbit at location")
visible: mainWindow.guidedControllerFlyView.showOrbit
onTriggered: {
orbitMapCircle.show(clickMenu.coord)
mainWindow.guidedControllerFlyView.confirmAction(mainWindow.guidedControllerFlyView.actionOrbit, clickMenu.coord, orbitMapCircle)
}
}
5 years ago
QGCMenuItem {
text: qsTr("ROI at location")
visible: mainWindow.guidedControllerFlyView.showROI
5 years ago
onTriggered: {
roiLocationItem.show(clickMenu.coord)
mainWindow.guidedControllerFlyView.confirmAction(mainWindow.guidedControllerFlyView.actionROI, clickMenu.coord, roiLocationItem)
5 years ago
}
}
}
onClicked: {
if (!mainWindow.guidedControllerFlyView.guidedUIVisible && (mainWindow.guidedControllerFlyView.showGotoLocation || mainWindow.guidedControllerFlyView.showOrbit || mainWindow.guidedControllerFlyView.showROI)) {
orbitMapCircle.hide()
gotoLocationItem.hide()
var clickCoord = _root.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
clickMenu.coord = clickCoord
clickMenu.popup()
}
}
}
// Airspace overlap support
MapItemView {
model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : []
delegate: MapCircle {
center: object.center
radius: object.radius
color: object.color
border.color: object.lineColor
border.width: object.lineWidth
}
}
MapItemView {
model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : []
delegate: MapPolygon {
path: object.polygon
color: object.color
border.color: object.lineColor
border.width: object.lineWidth
}
}
}