From d2c9f2e19b4e3eee56edb11e84eb63b4d195c2af Mon Sep 17 00:00:00 2001 From: MarekZegare4 Date: Thu, 25 Jun 2026 12:02:22 +0200 Subject: [PATCH] fix(ui): connect mini-map trail points with a line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Home "Map" page preview only plotted each trail vertex as a single pixel, leaving gaps wherever the streaming simplifier collapsed a straight stretch to its two endpoints — so a route looked like scattered dots instead of a path. The stale "gfx isn't available this early in the TU" comment no longer holds: GfxUtils.h is already reachable here, so draw the same Bresenham line the full Trail map uses. Extracted the shared "walk points, draw a line, break on TRAIL_FLAG_SEG_START" loop into gfx::drawTrail() (GfxUtils.h) so the full map and the mini-map preview don't carry two copies of it; they differ only in their projection and what (if anything) they draw at a segment break. Co-Authored-By: Claude Opus 4.8 --- examples/companion_radio/ui-new/GfxUtils.h | 22 +++++++++++++++++++ examples/companion_radio/ui-new/TrailScreen.h | 16 +++----------- examples/companion_radio/ui-new/UITask.cpp | 14 ++++++------ 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/examples/companion_radio/ui-new/GfxUtils.h b/examples/companion_radio/ui-new/GfxUtils.h index 59e03bc4..3970b645 100644 --- a/examples/companion_radio/ui-new/GfxUtils.h +++ b/examples/companion_radio/ui-new/GfxUtils.h @@ -6,6 +6,7 @@ #include #include // abs +#include "../Trail.h" namespace gfx { @@ -37,4 +38,25 @@ static inline void drawCircle(DisplayDriver& d, int cx, int cy, int r) { } } +// Walks a TrailStore and renders it as a connected polyline via drawLine(), +// breaking the line at each TRAIL_FLAG_SEG_START point (trail paused/ +// restarted) instead of bridging the dead-time gap. Shared by the full Trail +// map and the Home screen's mini-map preview, which only differ in how they +// project lat/lon to screen coords and what (if anything) they draw at a +// break. `project(lat, lon, x, y)` fills the screen coords for one point; +// `on_break(x_prev_end, y_prev_end, x_new_start, y_new_start)` runs at each +// break instead of drawLine() — pass a no-op lambda for a silent gap. +template +static void drawTrail(DisplayDriver& d, TrailStore& tr, Project project, OnBreak on_break) { + if (tr.count() == 0) return; + int x0, y0; project(tr.at(0).lat_1e6, tr.at(0).lon_1e6, x0, y0); + for (int i = 1; i < tr.count(); i++) { + const TrailPoint& pt = tr.at(i); + int x1, y1; project(pt.lat_1e6, pt.lon_1e6, x1, y1); + if (pt.flags & TRAIL_FLAG_SEG_START) on_break(x0, y0, x1, y1); + else drawLine(d, x0, y0, x1, y1); + x0 = x1; y0 = y1; + } +} + } // namespace gfx diff --git a/examples/companion_radio/ui-new/TrailScreen.h b/examples/companion_radio/ui-new/TrailScreen.h index 4810c02d..d2ca5b27 100644 --- a/examples/companion_radio/ui-new/TrailScreen.h +++ b/examples/companion_radio/ui-new/TrailScreen.h @@ -740,19 +740,9 @@ private: int x0, y0; proj.project(_store->at(0).lat_1e6, _store->at(0).lon_1e6, x0, y0); miniIconDrawCentered(display, x0, y0, ICON_MAP_DOT); - for (int i = 1; i < _store->count(); i++) { - const TrailPoint& pt = _store->at(i); - int x1, y1; - proj.project(pt.lat_1e6, pt.lon_1e6, x1, y1); - if (pt.flags & TRAIL_FLAG_SEG_START) { - drawFilledDot(display, x0, y0); - drawOpenDot(display, x1, y1); - } else { - gfx::drawLine(display, x0, y0, x1, y1); - } - x0 = x1; - y0 = y1; - } + gfx::drawTrail(display, *_store, + [&](int32_t la, int32_t lo, int& x, int& y) { proj.project(la, lo, x, y); }, + [&](int xa, int ya, int xb, int yb) { drawFilledDot(display, xa, ya); drawOpenDot(display, xb, yb); }); int sx, sy; proj.project(_store->first().lat_1e6, _store->first().lon_1e6, sx, sy); drawStartMarker(display, sx, sy); diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index ce1cf6fd..28ef3c88 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -34,6 +34,7 @@ #endif #include "icons.h" +#include "GfxUtils.h" // gfx::drawLine — connects trail points on the Home map preview // Blinking status indicators: on for the first half of a 4 s cycle, but e-ink // can't repaint fast enough to blink, so it shows them steadily. @@ -554,8 +555,9 @@ public: // Compact map preview for the Home "Map" page: own position, the GPS trail, // and live-tracked contacts (◆) folded into one auto-scaled box. A simplified - // cousin of TrailScreen's map (dots, no grid/labels) so the home carousel - // stays light. Returns false (and draws nothing) when there's nothing to show. + // cousin of TrailScreen's map (no grid/labels, no break markers) so the home + // carousel stays light. Returns false (and draws nothing) when there's + // nothing to show. bool drawMapPreview(DisplayDriver& display, int ax, int ay, int aw, int ah) { if (aw < 8 || ah < 8) return false; bool init = false; @@ -608,11 +610,9 @@ public: px = off_x + (int)((float)(lo - mnlo) * lon_scale * scale); py = off_y + (int)((float)(mxla - la) * scale); }; - // Trail as dots (no line — gfx isn't available this early in the TU). - for (int i = 0; i < tr.count(); i++) { - int px, py; project(tr.at(i).lat_1e6, tr.at(i).lon_1e6, px, py); - display.fillRect(px, py, 1, 1); - } + // Trail as a connected line, matching the full Trail map (shared helper — + // see gfx::drawTrail); no break marker here, just a silent gap. + gfx::drawTrail(display, tr, project, [](int, int, int, int) {}); for (int i = 0; i < LiveTrackStore::CAPACITY; i++) { if (!lt.isActive(i, now)) continue; int px, py; project(lt.slotAt(i).lat_1e6, lt.slotAt(i).lon_1e6, px, py);