mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
Add a single "Units" choice (Settings › System: Metric / Imperial) that governs every distance and speed shown in Tools — Nearby Nodes, the Trail views, and the navigate-to-point screen. - NodePrefs: units_imperial (global) + trail_show_pace (Trail readout mode), schema bumped 0xC0DE0005 → 0006. The old combined trail_units_idx is kept for file-layout stability but no longer drives anything; upgraders default to metric + speed. - geo::fmtDist gains an imperial mode (ft below ~1000 ft, then miles). - NavView / Nearby / Trail (waypoint list, Summary distance, List deltas, map scale-bar label) all format through the global preference. - Trail's action-menu "Units" row becomes a Speed/Pace readout toggle; the km-vs-mi unit now follows the global setting instead of being one of four combined options. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
2.4 KiB
C++
62 lines
2.4 KiB
C++
#pragma once
|
|
// Shared geographic helpers used by the navigation features (Nearby Nodes,
|
|
// Waypoints, trail course-over-ground). Coordinates are fixed-point degrees
|
|
// scaled by 1e6 (the same representation used by the GPS provider and the
|
|
// contact/trail records). All functions are pure and header-inline.
|
|
|
|
#include <Arduino.h>
|
|
#include <math.h>
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
namespace geo {
|
|
|
|
// Great-circle distance between two 1e6-scaled lat/lon points, in kilometres.
|
|
static inline float haversineKm(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2) {
|
|
static const float DEG2RAD = (float)M_PI / 180.0f;
|
|
float la1 = lat1 * (1e-6f * DEG2RAD);
|
|
float la2 = lat2 * (1e-6f * DEG2RAD);
|
|
float dla = (lat2 - lat1) * (1e-6f * DEG2RAD);
|
|
float dlo = (lon2 - lon1) * (1e-6f * DEG2RAD);
|
|
float a = sinf(dla/2)*sinf(dla/2) + cosf(la1)*cosf(la2)*sinf(dlo/2)*sinf(dlo/2);
|
|
return 6371.0f * 2.0f * asinf(sqrtf(a));
|
|
}
|
|
|
|
// Initial bearing from point 1 to point 2, degrees 0..359 (0 = north).
|
|
static inline int bearingDeg(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2) {
|
|
static const float DEG2RAD = (float)M_PI / 180.0f;
|
|
float la1 = lat1 * (1e-6f * DEG2RAD);
|
|
float la2 = lat2 * (1e-6f * DEG2RAD);
|
|
float dlo = (lon2 - lon1) * (1e-6f * DEG2RAD);
|
|
float b = atan2f(sinf(dlo)*cosf(la2),
|
|
cosf(la1)*sinf(la2) - sinf(la1)*cosf(la2)*cosf(dlo)) * (180.0f / (float)M_PI);
|
|
if (b < 0.0f) b += 360.0f;
|
|
return (int)(b + 0.5f) % 360;
|
|
}
|
|
|
|
// 8-point cardinal label for a bearing in degrees.
|
|
static inline const char* bearingCardinal(int deg) {
|
|
static const char* dirs[] = { "N","NE","E","SE","S","SW","W","NW" };
|
|
return dirs[((deg + 22) % 360) / 45];
|
|
}
|
|
|
|
// Human distance string. Metric: "850m" / "2.3km" / "140km". Imperial:
|
|
// "850ft" / "2.3mi" / "140mi" (feet below ~1000 ft, then miles).
|
|
static inline void fmtDist(char* buf, int n, float km, bool imperial) {
|
|
if (imperial) {
|
|
float ft = km * 3280.84f;
|
|
if (ft < 1000.0f) { snprintf(buf, n, "%dft", (int)(ft + 0.5f)); return; }
|
|
float mi = km * 0.621371f;
|
|
if (mi < 100.0f) snprintf(buf, n, "%.1fmi", mi);
|
|
else snprintf(buf, n, "%dmi", (int)(mi + 0.5f));
|
|
} else {
|
|
if (km < 1.0f) snprintf(buf, n, "%dm", (int)(km * 1000 + 0.5f));
|
|
else if (km < 100.0f) snprintf(buf, n, "%.1fkm", km);
|
|
else snprintf(buf, n, "%dkm", (int)(km + 0.5f));
|
|
}
|
|
}
|
|
|
|
} // namespace geo
|