QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GeoMapVehicleItem.qml
Go to the documentation of this file.
1/****************************************************************************
2 *
3 * (c) 2009-2024 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 *
5 * QGroundControl is licensed according to the terms in the file
6 * COPYING.md in the root of the source code directory.
7 *
8 ****************************************************************************/
9
10import QtQuick
11import QtQuick3D
12import QtPositioning
13
14import QGroundControl
15import QGroundControl.Controls
16import QGroundControl.GeoMap
17
18/// Vehicle marker for the GeoMap: 2D top-down icon that crossfades into a
19/// paper-airplane 3D model (heading/roll/pitch attitude) during the 2D<->3D
20/// terrain-scale transition. Anchored at true AMSL altitude, bias-corrected
21/// by the DEM-vs-home-AMSL offset so a landed vehicle sits exactly on the
22/// rendered mesh despite DEM/GPS disagreement.
23GeoMapItem {
24 id: root
25
26 property var vehicle
27 property real size: ScreenTools.defaultFontPixelHeight * 3
28
29 width: size
30 height: size
31 anchorPoint: Qt.point(width / 2, height / 2)
32 altitudeMode: GeoMapItem.Absolute
33 // coordinate.altitude (GLOBAL_POSITION_INT), not the altitudeAMSL fact:
34 // on PX4 the fact switches to the baro-frame ALTITUDE message, which
35 // disagrees with the GPS frame used by the trajectory and HOME_POSITION
36 coordinate: vehicle ? QtPositioning.coordinate(vehicle.coordinate.latitude,
37 vehicle.coordinate.longitude,
38 vehicle.coordinate.altitude + _homeTerrainBias)
39 : QtPositioning.coordinate()
40 visible: vehicle ? vehicle.coordinate.isValid : false
41
42 readonly property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
43 readonly property real _dimming: vehicle && vehicle === _activeVehicle ? 1.0 : 0.5
44 readonly property real _heading: vehicle && !isNaN(vehicle.heading.value) ? vehicle.heading.value : 0
45 readonly property real _roll: vehicle && !isNaN(vehicle.roll.value) ? vehicle.roll.value : 0
46 readonly property real _pitch: vehicle && !isNaN(vehicle.pitch.value) ? vehicle.pitch.value : 0
47 readonly property var _camera: scene ? scene.camera : null
48
49 // DEM height minus vehicle-reported AMSL, sampled at home. terrainHeightAt
50 // is not a binding dependency, so re-sampled explicitly below as terrain
51 // tiles arrive and when home moves.
52 property real _homeTerrainBias: 0
53
54 function _updateHomeTerrainBias() {
55 if (surfaceModel && vehicle && vehicle.homePosition.isValid && !isNaN(vehicle.homePosition.altitude)) {
56 _homeTerrainBias = surfaceModel.terrainDataHeightAt(vehicle.homePosition) - vehicle.homePosition.altitude
57 } else {
58 _homeTerrainBias = 0
59 }
60 }
61
62 onVehicleChanged: _updateHomeTerrainBias()
63 onSurfaceModelChanged: _updateHomeTerrainBias()
64
65 // Constant apparent size: scene units per screen pixel at the camera's
66 // look-at distance. Built-in QtQuick3D meshes are 100 units across.
67 readonly property real _modelScale: _camera
68 ? root.size * _camera.distance * _camera.unitsPerPixelAtUnitDistance / 100
69 : 1
70
71 Image {
72 id: vehicleIcon
73
74 anchors.fill: parent
75 source: root.vehicle ? root.vehicle.vehicleImageOpaque : ""
76 mipmap: true
77 sourceSize.width: root.size
78 fillMode: Image.PreserveAspectFit
79 opacity: root.contentOpacity2D * root._dimming
80 // Camera heading rotates map north on screen; the icon follows
81 rotation: root._heading + (root._camera ? root._camera.heading : 0)
82 }
83
84 delegate3D: Component {
85 // Paper-airplane dart matching the 2D icon. Scene axes are x east,
86 // y north, z up; heading is CW from north while positive z-rotation
87 // is CCW, hence the negation.
88 Node {
89 eulerRotation.z: -root._heading
90 scale: Qt.vector3d(root._modelScale, root._modelScale, root._modelScale)
91
92 Model {
93 eulerRotation.x: root._pitch
94 eulerRotation.y: root._roll
95 geometry: PaperPlaneGeometry {}
96 opacity: root._dimming
97
98 materials: PrincipledMaterial {
99 vertexColorsEnabled: true
100 cullMode: Material.NoCulling
101 }
102 }
103 }
104 }
105
106 Connections {
107 target: root.surfaceModel
108
109 function onTerrainDataChanged() {
110 root._updateHomeTerrainBias()
111 }
112 }
113
114 Connections {
115 target: root.vehicle
116
117 function onHomePositionChanged() {
118 root._updateHomeTerrainBias()
119 }
120 }
121}