Skip to content

Commit fc7d84f

Browse files
Build a vector of ptrs to use in composeMap() (#101)
Add background fill for missing tiles and improve map rendering alignment and speed - Fill regions with OSM_BGCOLOR when tiles are missing to prevent ghosting artifacts - Refactor composeMap for clarity and stability when handling incomplete tile sets
1 parent 70a03fa commit fc7d84f

File tree

2 files changed

+38
-37
lines changed

2 files changed

+38
-37
lines changed

src/OpenStreetMap-esp32.cpp

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,15 @@ CachedTile *OpenStreetMap::findUnusedTile(const tileList &requiredTiles, uint8_t
159159
return nullptr; // no unused tile found
160160
}
161161

162-
bool OpenStreetMap::isTileCachedOrBusy(uint32_t x, uint32_t y, uint8_t z)
162+
bool OpenStreetMap::isTileCached(uint32_t x, uint32_t y, uint8_t z, TileBufferList &tilePointers)
163163
{
164164
for (const auto &tile : tilesCache)
165165
{
166-
if (tile.x == x && tile.y == y && tile.z == z && (tile.valid || tile.busy))
166+
if (tile.x == x && tile.y == y && tile.z == z && tile.valid)
167+
{
168+
tilePointers.push_back(tile.buffer);
167169
return true;
170+
}
168171
}
169172
return false;
170173
}
@@ -197,30 +200,40 @@ bool OpenStreetMap::resizeTilesCache(uint16_t numberOfTiles)
197200
return true;
198201
}
199202

200-
void OpenStreetMap::updateCache(const tileList &requiredTiles, uint8_t zoom)
203+
void OpenStreetMap::updateCache(const tileList &requiredTiles, uint8_t zoom, TileBufferList &tilePointers)
201204
{
202205
[[maybe_unused]] const unsigned long startMS = millis();
203206
std::vector<TileJob> jobs;
204-
makeJobList(requiredTiles, jobs, zoom);
207+
makeJobList(requiredTiles, jobs, zoom, tilePointers);
205208
if (!jobs.empty())
206209
{
207210
runJobs(jobs);
208211
log_d("Updated %i tiles in %lu ms - %i ms/tile", jobs.size(), millis() - startMS, (millis() - startMS) / jobs.size());
209212
}
210213
}
211214

212-
void OpenStreetMap::makeJobList(const tileList &requiredTiles, std::vector<TileJob> &jobs, uint8_t zoom)
215+
void OpenStreetMap::makeJobList(const tileList &requiredTiles, std::vector<TileJob> &jobs, uint8_t zoom, TileBufferList &tilePointers)
213216
{
214217
for (const auto &[x, y] : requiredTiles)
215218
{
216-
if (isTileCachedOrBusy(x, y, zoom) || y < 0 || y >= (1 << zoom))
219+
if (y < 0 || y >= (1 << zoom))
220+
{
221+
tilePointers.push_back(nullptr); // we need to keep 1:1 grid alignment with requiredTiles for composeMap
222+
continue;
223+
}
224+
225+
if (isTileCached(x, y, zoom, tilePointers)) // isTileCached will push_back a valid ptr if tile is cached
217226
continue;
218227

219228
CachedTile *tileToReplace = findUnusedTile(requiredTiles, zoom);
220229
if (!tileToReplace)
221-
continue; // Should never happen if cache sizing is correct
230+
{
231+
tilePointers.push_back(nullptr); // again, keep 1:1 aligned
232+
continue;
233+
}
222234

223-
jobs.push_back({x, static_cast<uint32_t>(y), zoom, tileToReplace});
235+
tilePointers.push_back(tileToReplace->buffer); // push_back the still-to-download tile ptr
236+
jobs.push_back({x, static_cast<uint32_t>(y), zoom, tileToReplace}); // push_back tile ptr to the job list
224237
}
225238
}
226239

@@ -240,7 +253,7 @@ void OpenStreetMap::runJobs(const std::vector<TileJob> &jobs)
240253
vTaskDelay(pdMS_TO_TICKS(1));
241254
}
242255

243-
bool OpenStreetMap::composeMap(LGFX_Sprite &mapSprite, const tileList &requiredTiles, uint8_t zoom)
256+
bool OpenStreetMap::composeMap(LGFX_Sprite &mapSprite, TileBufferList &tilePointers)
244257
{
245258
if (mapSprite.width() != mapWidth || mapSprite.height() != mapHeight)
246259
{
@@ -255,30 +268,17 @@ bool OpenStreetMap::composeMap(LGFX_Sprite &mapSprite, const tileList &requiredT
255268
}
256269
}
257270

258-
int tileIndex = 0;
259-
for (const auto &[tileX, tileY] : requiredTiles)
271+
for (size_t tileIndex = 0; tileIndex < tilePointers.size(); ++tileIndex)
260272
{
261-
if (tileY < 0 || tileY >= (1 << zoom))
273+
const int drawX = startOffsetX + (tileIndex % numberOfColums) * currentProvider->tileSize;
274+
const int drawY = startOffsetY + (tileIndex / numberOfColums) * currentProvider->tileSize;
275+
const uint16_t *tile = tilePointers[tileIndex];
276+
if (!tile)
262277
{
263-
tileIndex++;
278+
mapSprite.fillRect(drawX, drawY, currentProvider->tileSize, currentProvider->tileSize, OSM_BGCOLOR);
264279
continue;
265280
}
266-
267-
int drawX = startOffsetX + (tileIndex % numberOfColums) * currentProvider->tileSize;
268-
int drawY = startOffsetY + (tileIndex / numberOfColums) * currentProvider->tileSize;
269-
270-
auto it = std::find_if(tilesCache.begin(), tilesCache.end(),
271-
[&](const CachedTile &tile)
272-
{
273-
return tile.x == tileX && tile.y == tileY && tile.z == zoom && tile.valid;
274-
});
275-
276-
if (it != tilesCache.end())
277-
mapSprite.pushImage(drawX, drawY, currentProvider->tileSize, currentProvider->tileSize, it->buffer);
278-
else
279-
log_w("Tile (z=%d, x=%d, y=%d) not found in cache", zoom, tileX, tileY);
280-
281-
tileIndex++;
281+
mapSprite.pushImage(drawX, drawY, currentProvider->tileSize, currentProvider->tileSize, tile);
282282
}
283283

284284
mapSprite.setTextColor(TFT_BLACK);
@@ -324,14 +324,13 @@ bool OpenStreetMap::fetchMap(LGFX_Sprite &mapSprite, double longitude, double la
324324
return false;
325325
}
326326

327-
updateCache(requiredTiles, zoom);
328-
329-
if (!composeMap(mapSprite, requiredTiles, zoom))
327+
TileBufferList tilePointers;
328+
updateCache(requiredTiles, zoom, tilePointers);
329+
if (!composeMap(mapSprite, tilePointers))
330330
{
331331
log_e("Failed to compose map");
332332
return false;
333333
}
334-
335334
return true;
336335
}
337336

src/OpenStreetMap-esp32.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "HTTPClientRAII.hpp"
4141
#include "fonts/DejaVu9-modded.h"
4242

43+
constexpr uint16_t OSM_BGCOLOR = lgfx::color565(100, 110, 120);
4344
constexpr uint16_t OSM_TILE_TIMEOUT_MS = 500;
4445
constexpr UBaseType_t OSM_TASK_PRIORITY = 1;
4546
constexpr uint32_t OSM_TASK_STACKSIZE = 5120;
@@ -50,6 +51,7 @@ constexpr int OSM_SINGLECORE_NUMBER = 1;
5051
static_assert(OSM_SINGLECORE_NUMBER < 2, "OSM_SINGLECORE_NUMBER must be 0 or 1 (ESP32 has only 2 cores)");
5152

5253
using tileList = std::vector<std::pair<uint32_t, int32_t>>;
54+
using TileBufferList = std::vector<uint16_t *>;
5355

5456
namespace
5557
{
@@ -101,16 +103,16 @@ class OpenStreetMap
101103
double lon2tile(double lon, uint8_t zoom);
102104
double lat2tile(double lat, uint8_t zoom);
103105
void computeRequiredTiles(double longitude, double latitude, uint8_t zoom, tileList &requiredTiles);
104-
void updateCache(const tileList &requiredTiles, uint8_t zoom);
106+
void updateCache(const tileList &requiredTiles, uint8_t zoom, TileBufferList &tilePointers);
105107
bool startTileWorkerTasks();
106-
void makeJobList(const tileList &requiredTiles, std::vector<TileJob> &jobs, uint8_t zoom);
108+
void makeJobList(const tileList &requiredTiles, std::vector<TileJob> &jobs, uint8_t zoom, TileBufferList &tilePointers);
107109
void runJobs(const std::vector<TileJob> &jobs);
108110
CachedTile *findUnusedTile(const tileList &requiredTiles, uint8_t zoom);
109-
bool isTileCachedOrBusy(uint32_t x, uint32_t y, uint8_t z);
111+
bool isTileCached(uint32_t x, uint32_t y, uint8_t z, TileBufferList &tilePointers);
110112
bool fetchTile(CachedTile &tile, uint32_t x, uint32_t y, uint8_t zoom, String &result);
111113
std::optional<std::unique_ptr<MemoryBuffer>> urlToBuffer(const char *url, String &result);
112114
bool fillBuffer(WiFiClient *stream, MemoryBuffer &buffer, size_t contentSize, String &result);
113-
bool composeMap(LGFX_Sprite &mapSprite, const tileList &requiredTiles, uint8_t zoom);
115+
bool composeMap(LGFX_Sprite &mapSprite,TileBufferList &tilePointers);
114116
static void tileFetcherTask(void *param);
115117
static void PNGDraw(PNGDRAW *pDraw);
116118

0 commit comments

Comments
 (0)