QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
ElevationTilePyramid.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
11
12#include <limits>
13#include <utility>
14
15#include "QGCLoggingCategory.h"
16
17QGC_LOGGING_CATEGORY(GeoMapElevationTilePyramidVerboseLog, "GeoMap.ElevationTilePyramid.Verbose")
18
19namespace {
20
23void adjustAncestorCounts(QHash<TileMath::TileKey, int>& counts, const TileMath::TileKey& key, int delta)
24{
25 for (int zoom = key.zoom - 1; zoom >= TileMath::kMinZoom; zoom--) {
26 const int shift = key.zoom - zoom;
27 const TileMath::TileKey ancestor{key.x >> shift, key.y >> shift, zoom};
28 const int count = counts.value(ancestor, 0) + delta;
29 if (count > 0) {
30 counts.insert(ancestor, count);
31 } else {
32 counts.remove(ancestor);
33 }
34 }
35}
36
37} // namespace
38
40{
41 if (!TileMath::isValidKey(key) || !grid.isValid()) {
42 return false;
43 }
44 const bool replacing = _tiles.contains(key);
45 if (!replacing && (_tiles.count() >= kMaxTiles)) {
46 const TileMath::TileKey evicted = _evictLeastRecentlyUsed();
47 if (TileMath::isValidKey(evicted) && evictedKey) {
48 *evictedKey = evicted;
49 }
50 }
51 _tiles.insert(key, std::move(grid));
52 _lastUsed.insert(key, ++_useTick);
53 if (!replacing) {
54 adjustAncestorCounts(_descendantCounts, key, +1);
55 }
56 return true;
57}
58
59TileMath::TileKey ElevationTilePyramid::_evictLeastRecentlyUsed()
60{
61 // Pinned tiles back rendered patches: never evict them. When everything
62 // is pinned there is no victim and the working set grows past the cap.
63 // O(tileCount) victim scan: fine at kMaxTiles, revisit if the cap grows
64 TileMath::TileKey lruKey{0, 0, -1};
65 qint64 lruTick = std::numeric_limits<qint64>::max();
66 for (auto it = _lastUsed.cbegin(); it != _lastUsed.cend(); ++it) {
67 if ((it.value() < lruTick) && !_pinnedKeys.contains(it.key())) {
68 lruTick = it.value();
69 lruKey = it.key();
70 }
71 }
72 if (!TileMath::isValidKey(lruKey)) {
73 qCDebug(GeoMapElevationTilePyramidVerboseLog)
74 << "all resident tiles pinned, growing past cap, tileCount" << _tiles.count();
75 return lruKey;
76 }
77 // Verbose: fires per insert once the working set is full
78 qCDebug(GeoMapElevationTilePyramidVerboseLog)
79 << "evicting least-recently-used tile" << lruKey << "tileCount" << _tiles.count();
80 _tiles.remove(lruKey);
81 _lastUsed.remove(lruKey);
82 adjustAncestorCounts(_descendantCounts, lruKey, -1);
83 return lruKey;
84}
85
87{
88 // Valid zoom bounds also cap the ancestor-shift distance below UB
89 if (!TileMath::isValidKey(key)) {
90 return View{};
91 }
92 _lookupCount++;
93 for (int zoom = key.zoom; zoom >= TileMath::kMinZoom; zoom--) {
94 const int shift = key.zoom - zoom;
95 const TileMath::TileKey candidate{key.x >> shift, key.y >> shift, zoom};
96 const auto it = _tiles.constFind(candidate);
97 if (it == _tiles.cend()) {
98 continue;
99 }
100 _lastUsed.insert(candidate, ++_useTick);
101 const double scale = 1.0 / (1LL << shift);
102 return View{&it.value(), candidate,
103 QRectF((key.x - (qint64(candidate.x) << shift)) * scale,
104 (key.y - (qint64(candidate.y) << shift)) * scale, scale, scale)};
105 }
106 return View{};
107}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
View bestTileFor(const TileMath::TileKey &key) const
bool insertTile(const TileMath::TileKey &key, Grid grid, TileMath::TileKey *evictedKey=nullptr)
static constexpr int kMaxTiles
bool isValidKey(const TileKey &key)
True if zoom is within [kMinZoom, kMaxZoom] and x/y address a tile at that zoom.
Definition TileMath.cc:44
constexpr int kMinZoom
Definition TileMath.h:30
Decoded elevation samples for one tile, row-major from the NW corner.