QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GeoMapFlightPath.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 flight-path trail for the GeoMap: a red 3D ribbon in the scene at
19/// true flight altitude, depth-tested so terrain occludes it. Width stays
20/// constant in screen pixels via vertex-shader expansion. Stays visible in 2D
21/// mode (crossfade3D off): the altitude offsets flatten with terrainScale so
22/// it renders as the classic flat trail line. Altitudes get the same
23/// DEM-vs-home-AMSL bias correction as GeoMapVehicleItem, applied at the
24/// anchor so the whole trail shifts with it.
25GeoMapItem {
26 id: root
27
28 property var vehicle
29 property real lineWidth: ScreenTools.defaultFontPixelHeight / 5
30 property color lineColor: "red"
31
32 altitudeMode: GeoMapItem.Absolute
33 crossfade3D: false
34 coordinate: {
35 if (!_geometry || !_geometry.anchorCoordinate.isValid) {
36 return QtPositioning.coordinate()
37 }
38 const anchor = _geometry.anchorCoordinate
39 return QtPositioning.coordinate(anchor.latitude, anchor.longitude, anchor.altitude + _homeTerrainBias)
40 }
41 visible: !!vehicle
42
43 // The geometry lives inside the 3D delegate (created/destroyed with the
44 // scene); this bridges its anchor out for the coordinate binding above
45 property var _geometry: null
46
47 readonly property var _camera: scene ? scene.camera : null
48
49 // Pixel-to-scene-unit factor at unit distance; the shader scales it by
50 // each vertex's own camera distance
51 readonly property real _screenFactor: _camera && _camera.viewportSize.height > 0
52 ? 2 * Math.tan(_camera.fieldOfView * Math.PI / 360) / _camera.viewportSize.height
53 : 0
54
55 // DEM height minus vehicle-reported AMSL, sampled at home (same
56 // correction as GeoMapVehicleItem so trail and marker stay aligned)
57 property real _homeTerrainBias: 0
58
59 function _updateHomeTerrainBias() {
60 if (surfaceModel && vehicle && vehicle.homePosition.isValid && !isNaN(vehicle.homePosition.altitude)) {
61 _homeTerrainBias = surfaceModel.terrainHeightAt(vehicle.homePosition) - vehicle.homePosition.altitude
62 } else {
63 _homeTerrainBias = 0
64 }
65 }
66
67 function _reloadPath() {
68 if (_geometry) {
69 _geometry.setPath(vehicle ? vehicle.trajectoryPoints.list() : [])
70 }
71 }
72
73 onVehicleChanged: {
74 _updateHomeTerrainBias()
75 _reloadPath()
76 }
77 onSurfaceModelChanged: _updateHomeTerrainBias()
78
79 delegate3D: Component {
80 // z offsets are relative altitudes; flatten them with the terrain
81 // during the 2D<->3D transition (anchor z already tracks terrainScale
82 // through GeoMapItem)
83 Node {
84 scale: Qt.vector3d(1, 1, root.scene ? root.scene.terrainScale : 1)
85
86 Model {
87 geometry: FlightPathGeometry {
88 id: pathGeometry
89
90 scene: root.scene
91 }
92
93 materials: CustomMaterial {
94 shadingMode: CustomMaterial.Unshaded
95 cullMode: Material.NoCulling
96 vertexShader: "shaders/flightpath.vert"
97 fragmentShader: "shaders/flightpath.frag"
98
99 property real lineWidth: root.lineWidth
100 property real screenFactor: root._screenFactor
101 property color pathColor: root.lineColor
102 // Ramps in as the terrain flattens, effectively disabling
103 // depth testing in 2D mode (see flightpath.vert)
104 property real depthPull: root.scene ? 0.5 * (1.0 - root.scene.terrainScale) : 0.0
105 }
106
107 Component.onCompleted: {
108 root._geometry = pathGeometry
109 root._reloadPath()
110 }
111 Component.onDestruction: root._geometry = null
112 }
113
114 Connections {
115 target: root.vehicle ? root.vehicle.trajectoryPoints : null
116
117 function onPointAdded(coordinate) { pathGeometry.appendPoint(coordinate) }
118 function onUpdateLastPoint(coordinate) { pathGeometry.updateLastPoint(coordinate) }
119 function onPointsCleared() { pathGeometry.clearPath() }
120 }
121 }
122 }
123
124 Connections {
125 target: root.surfaceModel
126
127 function onTerrainHeightsChanged() {
128 root._updateHomeTerrainBias()
129 }
130 }
131
132 Connections {
133 target: root.vehicle
134
135 function onHomePositionChanged() {
136 root._updateHomeTerrainBias()
137 }
138 }
139}