1/****************************************************************************
3 * (c) 2009-2024 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
5 * QGroundControl is licensed according to the terms in the file
6 * COPYING.md in the root of the source code directory.
8 ****************************************************************************/
14import QGroundControl.Controls
15import QGroundControl.FlightMap
16import QGroundControl.GeoMap
18/// GeoMap-engine drop-in for FlyViewMap: hosts a FlyViewGeoMap and implements
19/// the mapControl contract the Fly View overlays consume (pipState,
20/// isSatelliteMap, toCoordinate/fromCoordinate, zoomLevel, ...).
24 // mapControl contract (parity with FlyViewMap)
26 property Item pipState: _pipState
27 property var rightPanelWidth
28 property var planMasterController
29 property bool pipMode: false // true: map is shown in a small pip mode
30 property rect viewportRect: Qt.rect(0, 0, width, height) // Map area the vehicle is kept within
31 property var occluders: [] // Rects within the viewport covered by UI
32 property real chromeTopMargin: 0 // Map controls on the right edge start below this
33 property real chromeBottomMargin: 0 // Map overlays on the bottom left stay above this
34 property string mapName
36 // Writable center (contract parity with FlyViewMap): assignments recentre
37 // the camera; the camera Connections below keeps it tracking afterwards
39 readonly property real zoomLevel: {
40 // Viewport/FOV referenced so the invokable re-evaluates on resize
41 geoMapControl.camera.viewportSize
42 geoMapControl.camera.verticalFieldOfView
43 return geoMapControl.camera.zoomLevelForDistance(geoMapControl.camera.distance)
45 readonly property bool isSatelliteMap: _mapTypeSetting.indexOf("Satellite") > -1 || _mapTypeSetting.indexOf("Hybrid") > -1
46 property alias pinchZoomDisabledByVirtualJoysticks: geoMapControl.pinchZoomDisabledByVirtualJoysticks
48 // Escape hatch for GeoMap-specific chrome/controls
49 readonly property var geoMap: geoMapControl
51 readonly property string _mapTypeSetting: QGroundControl.settingsManager.flightMapSettings.mapType.rawValue
53 // PiP analog of FlyViewMap._adjustMapZoomForPipMode: pull the camera back
54 // 3 zoom levels in the small window for situational context; the swap-back
55 // resize re-applies the shared saved zoom. PiP is also too small for a useful
56 // 3D view, so force 2D and restore the previous camera mode with it.
57 property int _fullViewCameraMode: GeoMapCamera.Mode2D
60 const camera = geoMapControl.camera
62 _fullViewCameraMode = camera.mode
63 camera.mode = GeoMapCamera.Mode2D
64 camera.distance = camera.distanceForZoomLevel(camera.zoomLevelForDistance(camera.distance) - 3)
66 camera.mode = _fullViewCameraMode
70 // Map view shared with Plan view and persisted across restarts, as
71 // FlyViewMap does via QGroundControl.flightMapPosition/flightMapZoom
72 property bool _applyingSavedZoom: false
74 function _restoreSavedMapView() {
75 geoMapControl.camera.center = QGroundControl.flightMapPosition
79 // Zoom level -> distance depends on the viewport size, so this also runs on
80 // every resize: the zoom level is kept, as FlyViewMap does. PiP keeps its own zoom.
81 function _applySavedZoom() {
82 const camera = geoMapControl.camera
83 if (pipMode || camera.viewportSize.width <= 0 || camera.viewportSize.height <= 0) {
86 _applyingSavedZoom = true
87 camera.distance = camera.distanceForZoomLevel(QGroundControl.flightMapZoom)
88 _applyingSavedZoom = false
91 // Only the full-view zoom is saved: PiP distance changes are not
92 function _onCameraDistanceChanged() {
93 if (_applyingSavedZoom || !visible || pipMode) {
96 const camera = geoMapControl.camera
97 QGroundControl.flightMapZoom = camera.zoomLevelForDistance(camera.distance)
102 _restoreSavedMapView()
106 // Breaks the center <-> camera.center cycle: camera moves echo into
107 // center via the Connections below and must not be written back
108 property bool _echoingCameraCenter: false
111 if (_echoingCameraCenter || !center || !center.isValid) {
114 geoMapControl.camera.center = center
117 // Screen point -> coordinate of the rendered terrain surface under it
118 // (clipToViewPort accepted for signature parity, screen points are
119 // always inside the viewport for the fly view use cases)
120 function toCoordinate(point, clipToViewPort) {
121 return geoMapControl.surfaceCoordinateAt(point)
124 // Geographic coordinate -> screen point; invalid/behind-camera projects
125 // to an off-screen point so distance math degrades instead of throwing
126 function fromCoordinate(coordinate, clipToViewPort) {
127 const screenPos = geoMapControl.scene.screenPositionFor(coordinate)
128 return (screenPos === undefined) ? Qt.point(-1, -1) : screenPos
131 // MapFitFunctions contract (FlightMap.setVisibleRegion parity)
132 function setVisibleRegion(region) {
133 geoMapControl.fitToRegion(region)
134 // PiP zoom is otherwise never shared: save the fit so the swap back keeps it (FlyViewMap parity)
135 if (pipMode && visible) {
136 const camera = geoMapControl.camera
137 QGroundControl.flightMapZoom = camera.zoomLevelForDistance(camera.distance)
144 followViewportRect: root.viewportRect
145 followOccluders: root.occluders
147 // The PiP window is too small for free camera panning to be useful
148 keepVehicleCentered: root.pipMode || QGroundControl.settingsManager.flyViewSettings.keepMapCenteredOnVehicle.rawValue
150 // Guided-action popup on click (FlyViewMap.onMapClicked parity).
151 // Allowed at any tilt: toCoordinate picks the rendered terrain
152 // surface, so the click lands where the user sees it even in 3D.
153 onMapClicked: (position) => {
157 if (!globals.guidedControllerFlyView.guidedUIVisible &&
158 (globals.guidedControllerFlyView.showGotoLocation || globals.guidedControllerFlyView.showOrbit ||
159 globals.guidedControllerFlyView.showROI || globals.guidedControllerFlyView.showSetHome ||
160 globals.guidedControllerFlyView.showSetEstimatorOrigin)) {
162 const clickCoord = root.toCoordinate(Qt.point(position.x, position.y), false /* clipToViewPort */)
163 if (!clickCoord.isValid) {
166 const windowPosition = root.mapToItem(globals.parent, position.x, position.y)
167 const dropPanel = mapClickDropPanelComponent.createObject(mainWindow, { mapClickCoord: clickCoord, clickRect: Qt.rect(windowPosition.x, windowPosition.y, 0, 0) })
174 id: mapClickDropPanelComponent
176 FlyViewMapClickDropPanel {
177 gotoIndicator: geoMapControl.gotoIndicator
178 orbitIndicator: geoMapControl.orbitIndicator
182 ObstacleDistanceOverlayMap {
184 showText: !root.pipMode
187 FlyViewGeoMapChrome {
189 geoMap: geoMapControl
190 visible: !root.pipMode
191 buttonsTopMargin: root.chromeTopMargin
192 overlayBottomMargin: root.chromeBottomMargin
197 pipView: root.pipView
198 isDark: _isFullWindowItemDark
204 usePlannedHomePosition: false
205 planMasterController: root.planMasterController
208 // Zoom to a mission downloaded from the vehicle (FlyViewMap parity)
210 target: root.planMasterController ? root.planMasterController.missionController : null
212 function onNewItemsFromVehicle() {
213 const visualItems = root.planMasterController.missionController.visualItems
214 if (visualItems && visualItems.count !== 1) {
215 mapFitFunctions.fitMapViewportToMissionItems()
216 geoMapControl.positionTracker.firstVehiclePositionReceived = true
222 target: geoMapControl.camera
224 function onCenterChanged() {
225 root._echoingCameraCenter = true
226 root.center = geoMapControl.camera.center
227 root._echoingCameraCenter = false
228 // Hidden: don't overwrite the position another view is sharing
230 QGroundControl.flightMapPosition = geoMapControl.camera.center
234 function onDistanceChanged() {
235 root._onCameraDistanceChanged()
238 function onViewportSizeChanged() {
239 root._applySavedZoom()
243 Component.onCompleted: {
244 _restoreSavedMapView()
245 _echoingCameraCenter = true
246 center = geoMapControl.camera.center
247 _echoingCameraCenter = false