QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
SurfaceModel.h
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#pragma once
11
12#include <optional>
13
14#include <QtCore/QElapsedTimer>
15#include <QtCore/QHash>
16#include <QtCore/QList>
17#include <QtCore/QObject>
18#include <QtCore/QPointF>
19#include <QtCore/QRectF>
20#include <QtCore/QSet>
21#include <QtCore/QVarLengthArray>
22
23#include "TileMath.h"
24
25class GeoMapCamera;
26class HeightField;
27class HeightSource;
28
47class SurfaceModel : public QObject
48{
49 Q_OBJECT
50
51public:
52 SurfaceModel(GeoMapCamera* camera, HeightSource* heightSource, HeightField* field, QObject* parent = nullptr);
53
54 static constexpr int kGridSize = 16;
58 static constexpr int kMaxPatches = 256;
64 static constexpr int kMaxPatchAddsPerUpdate = 2;
69 static constexpr int kMaxPatchRemovalsPerUpdate = 4;
70 static constexpr double kRefinePixelThreshold = 384.0;
71 static constexpr double kMaxRangeMultiplier = 40.0;
72 static constexpr int kVisibleSampleGrid = 5;
75 static constexpr double kRecullHeightMargin = 25.0;
76
77 struct Patch
78 {
80 QList<float> heights;
83 bool ready = true;
84 bool covered = false;
85 float edgeStep = 0.0f;
86 QPointF edgeStepAt;
87 bool edgeCliff = false;
88 };
89
94 void update();
95
97 bool updateSettled() const { return !_updatePending && !_addsDeferred && !_removalsDeferred; }
98
99 QList<Patch> patches() const;
100
102 std::optional<Patch> patch(const TileMath::TileKey& key) const;
103
107 std::optional<double> renderedHeightAt(const QPointF& world) const;
108
112 QList<int> edgeLodDeltas(const TileMath::TileKey& key) const;
113
116 {
117 int updates = 0;
118 qint64 totalUs = 0;
119 qint64 maxUs = 0;
120 qint64 addTotalUs = 0;
121 qint64 addMaxUs = 0;
122 };
123
126
128 QRectF visibleGroundRect() const { return _visibleGroundRect(_maxTerrainZ()); }
129
130 int patchCount() const { return _patches.count(); }
131
134 int pendingCount() const { return 0; }
135
136#ifdef QGC_UNITTEST_BUILD
139 void drainUpdates()
140 {
141 int guard = kMaxPatches;
142 do {
143 update();
144 } while ((_addsDeferred || _removalsDeferred) && (--guard > 0));
145 }
146#endif
147
148signals:
159
160private slots:
161 void _fieldRegionChanged(const QRectF& worldRect);
162
163private:
164 struct PatchData
165 {
166 QList<float> heights;
167 float maxHeight = 0.0f;
168 qint64 cliffSinceMs = -1;
169 float edgeStep = 0.0f;
170 QPointF edgeStepAt;
171 bool edgeCliff = false;
172 };
173
176 static constexpr double kCliffLogSlope = 0.5;
177
178 void _samplePatch(const TileMath::TileKey& key, PatchData& data);
179
180 double _projectedPixels(const TileMath::TileKey& key, const QPointF& cameraGround, double cameraHeight) const;
181 QList<TileMath::TileKey> _desiredPatches(const QRectF& visible, const QPointF& cameraGround,
182 double cameraHeight) const;
183 QRectF _visibleGroundRect(double terrainZ) const;
184 double _maxTerrainZ() const;
185 int _edgeDelta(const TileMath::TileKey& key, int dx, int dy) const;
186 void _scheduleUpdate();
187
188 // update() phases (see update() for the pass structure)
189 struct AddResult
190 {
191 int adds = 0;
192 qint64 addUs = 0;
193 };
194
195 AddResult _addDesiredPatches(const QList<TileMath::TileKey>& desired, QVarLengthArray<QRectF, 8>& churnRects);
196 int _removeStalePatches(const QList<TileMath::TileKey>& desired, const QSet<TileMath::TileKey>& desiredSet,
197 QVarLengthArray<QRectF, 8>& churnRects);
198 void _notifyEdgeChurn(const QVarLengthArray<QRectF, 8>& churnRects);
199 void _repinAncestors();
200
201 GeoMapCamera* const _camera;
202 HeightSource* const _heightSource;
203 HeightField* const _field;
204 QHash<TileMath::TileKey, PatchData> _patches;
205 UpdateStats _updateStats;
206 bool _updatePending = false;
207 bool _addsDeferred = false;
208 bool _removalsDeferred = false;
209 double _culledTerrainZ = 0.0;
210 QElapsedTimer _cliffClock;
211};
static constexpr double kRecullHeightMargin
static constexpr int kMaxPatchAddsPerUpdate
void surfaceHeightsChanged()
static constexpr double kMaxRangeMultiplier
visible-range cap in camera distances
std::optional< Patch > patch(const TileMath::TileKey &key) const
Single-patch lookup; std::nullopt when the key is not resident.
static constexpr int kMaxPatchRemovalsPerUpdate
static constexpr int kGridSize
QList< Patch > patches() const
bool updateSettled() const
False while a scheduled update pass or deferred patch churn is outstanding.
std::optional< double > renderedHeightAt(const QPointF &world) const
void patchEdgeDeltasChanged(const TileMath::TileKey &key)
QList< int > edgeLodDeltas(const TileMath::TileKey &key) const
void patchRemoved(const TileMath::TileKey &key)
int pendingCount() const
static constexpr int kVisibleSampleGrid
int patchCount() const
void patchAdded(const TileMath::TileKey &key)
static constexpr double kRefinePixelThreshold
subdivide above this projected size
void patchMeshChanged(const TileMath::TileKey &key)
The patch's mesh content changed (heights re-sampled): consumers must re-pull heights.
QRectF visibleGroundRect() const
Estimated visible ground region in world meters (see class comment)
UpdateStats takeUpdateStats()
Returns the counters accumulated since the previous call and resets them.
static constexpr int kMaxPatches
float edgeStep
cliff monitor: largest in-patch edge step (m); 0 while off
TileMath::TileKey key
bool edgeCliff
cliff monitor: edgeStep is steep enough to log as a cliff
QPointF edgeStepAt
world position of edgeStep
bool covered
always false (see ready)
QList< float > heights
update() call/duration counters for the perf overlay
qint64 addTotalUs
time inside the patch-add loop (delegate creation share)