QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MapPositionTracker.cc
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
10#include "MapPositionTracker.h"
11
12#include "QGCLoggingCategory.h"
13
14QGC_LOGGING_CATEGORY(MapPositionTrackerLog, "QMLControls.MapPositionTracker")
15
16MapPositionTracker::MapPositionTracker(QObject* parent) : QObject(parent)
17{
18 _resumeTimer.setSingleShot(true);
19 _resumeTimer.setInterval(kResumeDelayMs);
20 connect(&_resumeTimer, &QTimer::timeout, this, &MapPositionTracker::_resumeFollowing);
21}
22
24{
25 if (_active == active) {
26 return;
27 }
28 _active = active;
29 emit activeChanged();
30 if (_active) {
31 // Re-run the one-shots for positions that arrived while inactive
32 if (!_evaluateVehicleOneShot()) {
33 _evaluateGCSOneShot();
34 }
35 }
36}
37
38void MapPositionTracker::setGcsPosition(const QGeoCoordinate& position)
39{
40 if (_gcsPosition == position) {
41 return;
42 }
43 _gcsPosition = position;
44 emit gcsPositionChanged();
45 _evaluateGCSOneShot();
46}
47
48void MapPositionTracker::setVehicleCoordinate(const QGeoCoordinate& coordinate)
49{
50 if (_vehicleCoordinate == coordinate) {
51 return;
52 }
53 _vehicleCoordinate = coordinate;
55 if (_evaluateVehicleOneShot()) {
56 return;
57 }
58 // Continuous hard follow
59 if (_active && _keepVehicleCentered && _vehicleCoordinate.isValid() && !_paused()) {
60 emit centerMap(_vehicleCoordinate, false);
61 }
62}
63
65{
66 if (_allowGCSLocationCenter == allow) {
67 return;
68 }
69 _allowGCSLocationCenter = allow;
71 if (allow) {
72 // A position may already be valid; don't leave the one-shot dormant
73 _evaluateGCSOneShot();
74 }
75}
76
78{
79 if (_allowVehicleLocationCenter == allow) {
80 return;
81 }
82 _allowVehicleLocationCenter = allow;
84 if (allow) {
85 // A position may already be valid; don't leave the one-shot dormant
86 _evaluateVehicleOneShot();
87 }
88}
89
91{
92 if (_centerGCSWhenVehicleValid == center) {
93 return;
94 }
95 _centerGCSWhenVehicleValid = center;
97}
98
100{
101 if (_keepVehicleCentered == keep) {
102 return;
103 }
104 _keepVehicleCentered = keep;
106}
107
109{
110 if (_userInteracting == interacting) {
111 return;
112 }
113 _userInteracting = interacting;
115 if (_userInteracting) {
116 _resumeTimer.stop();
117 qCDebug(MapPositionTrackerLog) << "user interaction started, following paused";
118 } else {
119 _resumeTimer.start();
120 }
121}
122
124{
125 if (_animating == animating) {
126 return;
127 }
128 _animating = animating;
129 emit animatingChanged();
130}
131
133{
134 if (_firstVehiclePositionReceived == received) {
135 return;
136 }
137 _firstVehiclePositionReceived = received;
139}
140
141bool MapPositionTracker::_evaluateVehicleOneShot()
142{
143 if (!_active || _firstVehiclePositionReceived || !_allowVehicleLocationCenter || !_vehicleCoordinate.isValid()) {
144 return false;
145 }
147 qCDebug(MapPositionTrackerLog) << "centering on first vehicle position";
148 emit centerMap(_vehicleCoordinate, true);
149 return true;
150}
151
152void MapPositionTracker::_evaluateGCSOneShot()
153{
154 if (!_active || _firstGCSPositionReceived || _firstVehiclePositionReceived || !_allowGCSLocationCenter ||
155 !_gcsPosition.isValid()) {
156 return;
157 }
158 // Deliberately latched even when no centering occurs below (legacy
159 // FlightMap parity): the one-shot is spent on the first valid fix
160 _firstGCSPositionReceived = true;
161 // Only center on the GCS when there is no vehicle to look at, or when the
162 // map is going to keep following the vehicle anyway
163 if (_keepVehicleCentered || _centerGCSWhenVehicleValid || !_vehicleCoordinate.isValid()) {
164 qCDebug(MapPositionTrackerLog) << "centering on first GCS position";
165 emit centerMap(_gcsPosition, false);
166 }
167}
168
169void MapPositionTracker::_resumeFollowing()
170{
171 qCDebug(MapPositionTrackerLog) << "following resumed after user interaction";
172 if (_active && _keepVehicleCentered && _vehicleCoordinate.isValid()) {
173 emit centerMap(_vehicleCoordinate, false);
174 }
175 // Inset following resumes on the consumer's next evaluateInsetFollow call
176}
177
178void MapPositionTracker::evaluateInsetFollow(const QPointF& vehicleScreenPoint, const QRectF& centerRect,
179 const QVariantList& cornerRects)
180{
181 if (!_active || _keepVehicleCentered || !_firstVehiclePositionReceived || !_vehicleCoordinate.isValid() ||
182 _paused() || _animating) {
183 return;
184 }
185 bool recenterNeeded = !centerRect.contains(vehicleScreenPoint);
186 if (!recenterNeeded) {
187 // Inside the center rect, but possibly hidden under a corner UI element
188 for (const QVariant& rect : cornerRects) {
189 if (rect.toRectF().contains(vehicleScreenPoint)) {
190 recenterNeeded = true;
191 break;
192 }
193 }
194 }
195 if (recenterNeeded) {
196 emit recenterVehicleTo(centerRect.center());
197 }
198}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void setFirstVehiclePositionReceived(bool received)
void setAllowVehicleLocationCenter(bool allow)
bool animating() const
Consumer's recenter animation is running: inset evaluation is skipped.
void setVehicleCoordinate(const QGeoCoordinate &coordinate)
void setActive(bool active)
void setUserInteracting(bool interacting)
Q_INVOKABLE void evaluateInsetFollow(const QPointF &vehicleScreenPoint, const QRectF &centerRect, const QVariantList &cornerRects)
void keepVehicleCenteredChanged()
void userInteractingChanged()
void setCenterGCSWhenVehicleValid(bool center)
void setAllowGCSLocationCenter(bool allow)
void recenterVehicleTo(const QPointF &screenPoint)
Consumer moves the map (animated) so the vehicle lands at screenPoint.
void setGcsPosition(const QGeoCoordinate &position)
void firstVehiclePositionReceivedChanged()
void allowVehicleLocationCenterChanged()
void setKeepVehicleCentered(bool keep)
void setAnimating(bool animating)
void vehicleCoordinateChanged()
void centerMap(const QGeoCoordinate &coordinate, bool firstPosition)
void centerGCSWhenVehicleValidChanged()
void allowGCSLocationCenterChanged()