fix(map): L2 packet flow lines meet the marks too - PacketFlow::pointNow()

A flow's point is where its contact is now, its end here where you are now
(GPS, else the position set in Privacy): shared by the L2 map and the
OLED / e-ink Nodes map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-15 15:42:14 +02:00
co-authored by Claude Opus 5.5
parent 0346cebaf6
commit d85a3a1eef
3 changed files with 27 additions and 10 deletions
@@ -88,6 +88,20 @@ public:
int count() const { return _n; }
// i = 0 is the newest.
const Flow& at(int i) const { return _flows[(_head + MAX_FLOWS - 1 - i) % MAX_FLOWS]; }
// Where point k of a flow is now: a contact where it is now, the end here
// (no contact) where you are now -- not where they were when it was heard,
// so the lines meet the map's marks after a node moved or the GPS wandered.
void pointNow(const Flow& f, int k, int32_t& lat, int32_t& lon) const {
lat = f.lat[k]; lon = f.lon[k];
if (f.node[k] >= 0) {
ContactInfo c;
if (the_mesh.getContactByIdx(f.node[k], c) && (c.gps_lat || c.gps_lon)) { lat = c.gps_lat; lon = c.gps_lon; }
} else if (k == f.n - 1) {
int32_t a, b;
if (ownPosition(a, b)) { lat = a; lon = b; }
}
}
// Anything younger than `life_ms`?
bool active(uint32_t life_ms) const { return _n > 0 && millis() - at(0).t_ms < life_ms; }
+11 -3
View File
@@ -320,6 +320,14 @@ static void flowLegendRefresh() {
lv_obj_remove_flag(s_flow_legend, LV_OBJ_FLAG_HIDDEN);
}
static void flowPx(int32_t lat, int32_t lon, int32_t& x, int32_t& y);
// Point k of a flow on the layer, where its node and you are now (PacketFlow::pointNow).
static void flowPt(const PacketFlow::Flow& f, int k, int32_t& x, int32_t& y) {
int32_t lat, lon;
s_flow->pointNow(f, k, lat, lon);
flowPx(lat, lon, x, y);
}
static void flowPx(int32_t lat, int32_t lon, int32_t& x, int32_t& y) {
double fx = lonToTileX(lon / 1e6, s_view_z) * TILE_PX - s_view_left;
double fy = latToTileY(lat / 1e6, s_view_z) * TILE_PX - s_view_top;
@@ -337,7 +345,7 @@ static bool flowArea(lv_area_t& r) {
if (now - f.t_fade >= FLOW_LIFE) continue; // (an older one may live on with a newer copy)
for (int k = 0; k < f.n; k++) {
int32_t x, y;
flowPx(f.lat[k], f.lon[k], x, y);
flowPt(f, k, x, y);
if (!any) { r = { x, y, x, y }; any = true; }
r.x1 = min(r.x1, x); r.y1 = min(r.y1, y); r.x2 = max(r.x2, x); r.y2 = max(r.y2, y);
}
@@ -366,7 +374,7 @@ static void drawFlowNodes(lv_layer_t* layer, const lv_area_t& a, uint32_t now) {
if (j < nn) { if (opa > nodes[j].opa) nodes[j].opa = opa; continue; }
if (nn == (int)(sizeof(nodes) / sizeof(nodes[0]))) continue;
int32_t x, y;
flowPx(f.lat[k], f.lon[k], x, y);
flowPt(f, k, x, y);
nodes[nn++] = { f.node[k], opa, a.x1 + x, a.y1 + y, f.kind };
}
}
@@ -435,7 +443,7 @@ static void drawFlows(lv_layer_t* layer, const lv_area_t& a) {
if (fade >= FLOW_LIFE) continue;
const lv_color_t col = lv_color_hex(flowColour(f.kind));
int32_t px[PacketFlow::MAX_PTS], py[PacketFlow::MAX_PTS];
for (int k = 0; k < f.n; k++) { flowPx(f.lat[k], f.lon[k], px[k], py[k]); px[k] += a.x1; py[k] += a.y1; }
for (int k = 0; k < f.n; k++) { flowPt(f, k, px[k], py[k]); px[k] += a.x1; py[k] += a.y1; }
if (f.n == 1) { // a pulse
if (age >= PULSE_MS) continue;
ring.color = col;
@@ -988,13 +988,8 @@ class NearbyScreen : public UIScreen, protected NearbyModel {
if (millis() - f.t_ms > FLOW_SHOW_MS) break; // newest first
float px[PacketFlow::MAX_PTS], py[PacketFlow::MAX_PTS];
for (int k = 0; k < f.n; k++) {
int32_t la = f.lat[k], lo = f.lon[k];
ContactInfo c;
if (f.node[k] >= 0) { // a contact: where its dot is now
if (the_mesh.getContactByIdx(f.node[k], c) && (c.gps_lat || c.gps_lon)) { la = c.gps_lat; lo = c.gps_lon; }
} else if (me && k == f.n - 1) { // the last point, no contact: here
la = mla; lo = mlo;
}
int32_t la, lo;
fl.pointNow(f, k, la, lo);
projectF(la, lo, px[k], py[k]);
}
if (f.n == 1) { // a packet nothing of which could be placed: a ring here, briefly