Skip to content

Commit e1597f2

Browse files
committed
feat(GeoMap): map item overlays with 3D vehicle marker and flight path ribbon
Map item framework and first consumers for the GeoMap 3D engine: - GeoMapItem: screen-space 2D overlay items with altitude modes (ClampToSurface/RelativeToSurface/Absolute), optional delegate3D scene node with 2D<->3D crossfade (and crossfade3D opt-out for items with no 2D counterpart), teardrop GeoMapPin, shared auto-centering - GeoMapVehicleItem: vehicle marker with paper-airplane 3D model; uses coordinate.altitude (GPS frame) instead of the altitudeAMSL fact, which diverges to baro frame on PX4 - GeoMapFlightPath: vehicle trajectory rendered as a camera-facing ribbon; FlightPathGeometry keeps an incremental vertex buffer (O(1) append/update with partial GPU upload); shaders expand perpendicular to tangent and view direction so vertical climbs stay visible, with depth pull to defeat residual terrain height in 2D mode - TrajectoryPoints: 3D distance gate and east/north/up direction colinearity so purely vertical flight generates trajectory points; flight distance now accumulates through-the-air (3D) distance - GeoScene/GeoMapCamera: recenter solve at the point's rendered height with terrain-following pivot elevation; terrain-following look-at keeps the close-zoom 3D camera above the mesh - Tests: GeoMapItem lifecycle/crossfade, FlightPathGeometry incremental == rebuild equivalence, TrajectoryPoints vertical motion/decimation/3D distance, GeoScene solve round-trip and elevation units
1 parent e409a94 commit e1597f2

47 files changed

Lines changed: 3626 additions & 149 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/FlightMap/FlightMap.qml

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ Map {
1818
property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1
1919
property var gcsPosition: QGroundControl.qgcPositionManger.gcsPosition
2020
property real gcsHeading: QGroundControl.qgcPositionManger.gcsHeading
21-
property bool allowGCSLocationCenter: false ///< true: map will center/zoom to gcs location one time
22-
property bool allowVehicleLocationCenter: false ///< true: map will center/zoom to vehicle location one time
23-
property bool firstGCSPositionReceived: false ///< true: first gcs position update was responded to
24-
property bool firstVehiclePositionReceived: false ///< true: first vehicle position update was responded to
21+
property alias allowGCSLocationCenter: _positionTracker.allowGCSLocationCenter ///< true: map will center to gcs location one time
22+
property alias allowVehicleLocationCenter: _positionTracker.allowVehicleLocationCenter ///< true: map will center/zoom to vehicle location one time
23+
property alias firstVehiclePositionReceived: _positionTracker.firstVehiclePositionReceived ///< true: first vehicle position update was responded to
24+
property alias positionTracker: _positionTracker ///< Auto-centering policy, for derived maps to layer follow behavior on
2525
property bool planView: false ///< true: map being using for Plan view, items should be draggable
2626
property bool pinchZoomDisabledByVirtualJoysticks: false ///< true: disable pinch-to-zoom while virtual joystick thumbs are down
2727

@@ -40,18 +40,26 @@ Map {
4040
}
4141
}
4242

43-
function _possiblyCenterToVehiclePosition() {
44-
if (!firstVehiclePositionReceived && allowVehicleLocationCenter && _activeVehicleCoordinate.isValid) {
45-
firstVehiclePositionReceived = true
46-
center = _activeVehicleCoordinate
47-
zoomLevel = QGroundControl.flightMapInitialZoom
48-
}
49-
}
50-
5143
function centerToSpecifiedLocation() {
5244
specifyMapPositionDialogFactory.open()
5345
}
5446

47+
MapPositionTracker {
48+
id: _positionTracker
49+
50+
active: _map.mapReady
51+
gcsPosition: _map.gcsPosition
52+
vehicleCoordinate: _map._activeVehicleCoordinate
53+
centerGCSWhenVehicleValid: QGroundControl.settingsManager.flyViewSettings.keepMapCenteredOnVehicle.rawValue
54+
55+
onCenterMap: (coordinate, firstPosition) => {
56+
_map.center = coordinate
57+
if (firstPosition) {
58+
_map.zoomLevel = QGroundControl.flightMapInitialZoom
59+
}
60+
}
61+
}
62+
5563
QGCPopupDialogFactory {
5664
id: specifyMapPositionDialogFactory
5765

@@ -67,17 +75,6 @@ Map {
6775
}
6876
}
6977

70-
// Center map to gcs location
71-
onGcsPositionChanged: {
72-
if (gcsPosition.isValid && allowGCSLocationCenter && !firstGCSPositionReceived && !firstVehiclePositionReceived) {
73-
firstGCSPositionReceived = true
74-
//-- Only center on gsc if we have no vehicle (and we are supposed to do so)
75-
var _activeVehicleCoordinate = _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
76-
if(QGroundControl.settingsManager.flyViewSettings.keepMapCenteredOnVehicle.rawValue || !_activeVehicleCoordinate.isValid)
77-
center = gcsPosition
78-
}
79-
}
80-
8178
function updateActiveMapType() {
8279
var settings = QGroundControl.settingsManager.flightMapSettings
8380
var fullMapName = settings.mapProvider.value + " " + settings.mapType.value
@@ -90,12 +87,9 @@ Map {
9087
}
9188
}
9289

93-
on_ActiveVehicleCoordinateChanged: _possiblyCenterToVehiclePosition()
94-
9590
onMapReadyChanged: {
9691
if (_map.mapReady) {
9792
updateActiveMapType()
98-
_possiblyCenterToVehiclePosition()
9993
}
10094
}
10195

src/FlyView/FlyViewGeoMap.qml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,44 @@
77
*
88
****************************************************************************/
99

10+
import QtPositioning
11+
12+
import QGroundControl
1013
import QGroundControl.GeoMap
1114

1215
/// Fly-view 2D/3D map: the GeoMap-engine counterpart of FlyViewMap.
1316
/// Fly-view specific map content (vehicle items, trajectory, ...) lands here.
1417
GeoMap {
18+
id: root
19+
20+
allowGCSLocationCenter: true
21+
allowVehicleLocationCenter: true
22+
keepVehicleCentered: QGroundControl.settingsManager.flyViewSettings.keepMapCenteredOnVehicle.rawValue
23+
24+
readonly property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
25+
26+
// Vehicle home (launch) location
27+
GeoMapPin {
28+
scene: root.scene
29+
surfaceModel: root.surfaceModel
30+
coordinate: root._activeVehicle ? root._activeVehicle.homePosition : QtPositioning.coordinate()
31+
visible: root._activeVehicle && root._activeVehicle.homePosition.isValid
32+
label: qsTr("L")
33+
}
34+
35+
Repeater {
36+
model: QGroundControl.multiVehicleManager.vehicles
37+
38+
GeoMapVehicleItem {
39+
scene: root.scene
40+
surfaceModel: root.surfaceModel
41+
vehicle: object
42+
}
43+
}
44+
45+
GeoMapFlightPath {
46+
scene: root.scene
47+
surfaceModel: root.surfaceModel
48+
vehicle: root._activeVehicle
49+
}
1550
}

src/FlyView/FlyViewMap.qml

Lines changed: 43 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ FlightMap {
3636
property var _flyViewSettings: QGroundControl.settingsManager.flyViewSettings
3737
property bool _keepMapCenteredOnVehicle: _flyViewSettings.keepMapCenteredOnVehicle.rawValue
3838

39-
property bool _disableVehicleTracking: false
4039
property bool _keepVehicleCentered: pipMode ? true : false
4140
property bool _saveZoomLevelSetting: true
4241

@@ -71,14 +70,33 @@ FlightMap {
7170
}
7271

7372
// We track whether the user has panned or not to correctly handle automatic map positioning
74-
onMapPanStart: _disableVehicleTracking = true
75-
onMapPanStop: panRecenterTimer.restart()
73+
onMapPanStart: positionTracker.userInteracting = true
74+
onMapPanStop: positionTracker.userInteracting = false
7675

77-
function pointInRect(point, rect) {
78-
return point.x > rect.x &&
79-
point.x < rect.x + rect.width &&
80-
point.y > rect.y &&
81-
point.y < rect.y + rect.height;
76+
// Follow behavior on top of FlightMap's one-shot centering: hard follow while
77+
// the keep-centered setting or pip mode is active, inset-rect follow otherwise
78+
Binding {
79+
target: positionTracker
80+
property: "keepVehicleCentered"
81+
value: _keepMapCenteredOnVehicle || _keepVehicleCentered
82+
}
83+
84+
Binding {
85+
target: positionTracker
86+
property: "animating"
87+
value: animateLat.running || animateLong.running
88+
}
89+
90+
Connections {
91+
target: positionTracker
92+
function onRecenterVehicleTo(screenPoint) {
93+
// Move the map such that the vehicle lands on screenPoint
94+
let vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
95+
let centerOffset = Qt.point((_root.width / 2) - screenPoint.x, (_root.height / 2) - screenPoint.y)
96+
let vehicleOffsetPoint = Qt.point(vehiclePoint.x + centerOffset.x, vehiclePoint.y + centerOffset.y)
97+
let vehicleOffsetCoord = _root.toCoordinate(vehicleOffsetPoint, false /* clipToViewport */)
98+
animatedMapRecenter(_root.center, vehicleOffsetCoord)
99+
}
82100
}
83101

84102
property real _animatedLatitudeStart
@@ -115,76 +133,19 @@ FlightMap {
115133
// returns the four rectangles formed by the 8 corner insets
116134
// used for detecting if the vehicle has flown under the instrument panel, virtual joystick etc
117135
function _insetCornerRects() {
118-
var rects = {
119-
"topleft": Qt.rect(0,0,
120-
toolInsets.leftEdgeTopInset,
121-
toolInsets.topEdgeLeftInset),
122-
"topright": Qt.rect(_root.width-toolInsets.rightEdgeTopInset,0,
123-
toolInsets.rightEdgeTopInset,
124-
toolInsets.topEdgeRightInset),
125-
"bottomleft": Qt.rect(0,_root.height-toolInsets.bottomEdgeLeftInset,
126-
toolInsets.leftEdgeBottomInset,
127-
toolInsets.bottomEdgeLeftInset),
128-
"bottomright": Qt.rect(_root.width-toolInsets.rightEdgeBottomInset,_root.height-toolInsets.bottomEdgeRightInset,
129-
toolInsets.rightEdgeBottomInset,
130-
toolInsets.bottomEdgeRightInset)}
131-
return rects
132-
}
133-
134-
function recenterNeeded() {
135-
var vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
136-
var centerRect = _insetCenterRect()
137-
//return !pointInRect(vehiclePoint,insetRect)
138-
139-
// If we are outside the center inset rectangle, recenter
140-
if(!pointInRect(vehiclePoint, centerRect)){
141-
return true
142-
}
143-
144-
// if we are inside the center inset rectangle
145-
// then additionally check if we are underneath one of the corner inset rectangles
146-
var cornerRects = _insetCornerRects()
147-
if(pointInRect(vehiclePoint, cornerRects["topleft"])){
148-
return true
149-
} else if(pointInRect(vehiclePoint, cornerRects["topright"])){
150-
return true
151-
} else if(pointInRect(vehiclePoint, cornerRects["bottomleft"])){
152-
return true
153-
} else if(pointInRect(vehiclePoint, cornerRects["bottomright"])){
154-
return true
155-
}
156-
157-
// if we are inside the center inset rectangle, and not under any corner elements
158-
return false
159-
}
160-
161-
function updateMapToVehiclePosition() {
162-
if (animateLat.running || animateLong.running) {
163-
return
164-
}
165-
// We let FlightMap handle first vehicle position
166-
if (!_keepMapCenteredOnVehicle && firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
167-
if (_keepVehicleCentered) {
168-
_root.center = _activeVehicleCoordinate
169-
} else {
170-
if (firstVehiclePositionReceived && recenterNeeded()) {
171-
// Move the map such that the vehicle is centered within the inset area
172-
var vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
173-
var centerInsetRect = _insetCenterRect()
174-
var centerInsetPoint = Qt.point(centerInsetRect.x + centerInsetRect.width / 2, centerInsetRect.y + centerInsetRect.height / 2)
175-
var centerOffset = Qt.point((_root.width / 2) - centerInsetPoint.x, (_root.height / 2) - centerInsetPoint.y)
176-
var vehicleOffsetPoint = Qt.point(vehiclePoint.x + centerOffset.x, vehiclePoint.y + centerOffset.y)
177-
var vehicleOffsetCoord = _root.toCoordinate(vehicleOffsetPoint, false /* clipToViewport */)
178-
animatedMapRecenter(_root.center, vehicleOffsetCoord)
179-
}
180-
}
181-
}
182-
}
183-
184-
on_ActiveVehicleCoordinateChanged: {
185-
if (_keepMapCenteredOnVehicle && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) {
186-
_root.center = _activeVehicleCoordinate
187-
}
136+
return [
137+
Qt.rect(0,0,
138+
toolInsets.leftEdgeTopInset,
139+
toolInsets.topEdgeLeftInset),
140+
Qt.rect(_root.width-toolInsets.rightEdgeTopInset,0,
141+
toolInsets.rightEdgeTopInset,
142+
toolInsets.topEdgeRightInset),
143+
Qt.rect(0,_root.height-toolInsets.bottomEdgeLeftInset,
144+
toolInsets.leftEdgeBottomInset,
145+
toolInsets.bottomEdgeLeftInset),
146+
Qt.rect(_root.width-toolInsets.rightEdgeBottomInset,_root.height-toolInsets.bottomEdgeRightInset,
147+
toolInsets.rightEdgeBottomInset,
148+
toolInsets.bottomEdgeRightInset)]
188149
}
189150

190151
PipState {
@@ -193,21 +154,14 @@ FlightMap {
193154
isDark: _isFullWindowItemDark
194155
}
195156

196-
Timer {
197-
id: panRecenterTimer
198-
interval: 10000
199-
running: false
200-
onTriggered: {
201-
_disableVehicleTracking = false
202-
updateMapToVehiclePosition()
203-
}
204-
}
205-
206157
Timer {
207158
interval: 500
208159
running: true
209160
repeat: true
210-
onTriggered: updateMapToVehiclePosition()
161+
onTriggered: {
162+
let vehiclePoint = _root.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */)
163+
positionTracker.evaluateInsetFollow(vehiclePoint, _insetCenterRect(), _insetCornerRects())
164+
}
211165
}
212166

213167
QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }

src/GeoMap/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,16 @@ qt_add_qml_module(GeoMapModule
3838
SOURCES
3939
CheckerboardTextureData.cc
4040
CheckerboardTextureData.h
41+
FlightPathGeometry.cc
42+
FlightPathGeometry.h
4143
GeoScene.cc
4244
GeoScene.h
4345
GeoMapCamera.cc
4446
GeoMapCamera.h
47+
GeoMapItem.cc
48+
GeoMapItem.h
49+
PaperPlaneGeometry.cc
50+
PaperPlaneGeometry.h
4551
PatchGeometry.cc
4652
PatchGeometry.h
4753
PatchTextureData.cc
@@ -50,6 +56,12 @@ qt_add_qml_module(GeoMapModule
5056
SurfacePatchModel.h
5157
QML_FILES
5258
GeoMap.qml
59+
GeoMapFlightPath.qml
60+
GeoMapPin.qml
61+
GeoMapVehicleItem.qml
62+
RESOURCES
63+
shaders/flightpath.frag
64+
shaders/flightpath.vert
5365
)
5466

5567
target_link_libraries(GeoMapModule
@@ -58,6 +70,7 @@ target_link_libraries(GeoMapModule
5870
Qt6::Gui
5971
Qt6::Positioning
6072
Qt6::Qml
73+
Qt6::Quick
6174
Qt6::Quick3D
6275
PRIVATE
6376
QGCLogging

0 commit comments

Comments
 (0)