mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-09-21 03:04:21 +00:00
Match the shell initialization call inside run() so its failure guard does not break the network-independence contract. Preserve initialization ordering and blocking-network checks. Apply clang-format 14 to the web preview sources. Verified all 2107 CI-scoped source files and seven positive/negative startup contract cases.
200 lines
8.0 KiB
C++
200 lines
8.0 KiB
C++
// Synchronous browser filesystem adapter for the production MapViewport.
|
|
// Tile positions follow the existing Linux adapter and shared Mercator helpers.
|
|
// No page controls, overlays, labels, fonts or styles are defined here.
|
|
#include "ui/widgets/map/map_tiles.h"
|
|
#include "ui_map_runtime/map_tiles/map_tile_geometry.h"
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
static uint8_t source_id = 0;
|
|
static bool contours = false;
|
|
static bool missing = false;
|
|
static double world_size(int z) { return std::ldexp(256.0, z); }
|
|
static double world_x(double lon, int z) { return (lon + 180.0) / 360.0 * world_size(z); }
|
|
static double world_y(double lat, int z)
|
|
{
|
|
lat = std::clamp(lat, -85.05112878, 85.05112878);
|
|
const double s = std::sin(lat * M_PI / 180.0);
|
|
return (.5 - std::log((1 + s) / (1 - s)) / (4 * M_PI)) * world_size(z);
|
|
}
|
|
static void world_geo(double x, double y, int z, double& lat, double& lon)
|
|
{
|
|
const double size = world_size(z);
|
|
lon = x / size * 360 - 180;
|
|
lat = std::atan(std::sinh(M_PI * (1 - 2 * y / size))) * 180 / M_PI;
|
|
}
|
|
void normalize_tile(int z, int& x, int& y) { ui::map_tiles::normalizeTile(z, x, y); }
|
|
void latLngToTile(double lat, double lon, int zoom, int& x, int& y) { ui::map_tiles::latLngToTile(lat, lon, zoom, x, y); }
|
|
void tileToLatLng(int x, int y, int zoom, double& lat, double& lon) { world_geo(x * 256.0, y * 256.0, zoom, lat, lon); }
|
|
void tileToPixel(int x, int y, int, int& px, int& py)
|
|
{
|
|
px = x * 256;
|
|
py = y * 256;
|
|
}
|
|
uint8_t sanitize_map_source(uint8_t source) { return source < 3 ? source : 0; }
|
|
const char* map_source_label(uint8_t source) { return source == 1 ? "Terrain" : source == 2 ? "Satellite"
|
|
: "OSM"; }
|
|
bool build_base_tile_path(int z, int x, int y, uint8_t source, char* out, size_t n)
|
|
{
|
|
const char* key = source == 1 ? "terrain" : source == 2 ? "satellite"
|
|
: "osm";
|
|
return std::snprintf(out, n, "A:/maps/base/%s/%d/%d/%d.png", key, z, x, y) > 0;
|
|
}
|
|
bool build_contour_tile_path(int z, int x, int y, char* out, size_t n) { return std::snprintf(out, n, "A:/maps/contour/major-50/%d/%d/%d.png", z, x, y) > 0; }
|
|
static bool exists(const char* path)
|
|
{
|
|
FILE* f = std::fopen(path + 2, "rb");
|
|
if (!f) return false;
|
|
std::fclose(f);
|
|
return true;
|
|
}
|
|
bool base_tile_available(int z, int x, int y, uint8_t source)
|
|
{
|
|
char path[180];
|
|
build_base_tile_path(z, x, y, source, path, sizeof(path));
|
|
return exists(path);
|
|
}
|
|
bool map_source_directory_available(uint8_t source) { return source < 3; }
|
|
bool contour_directory_available() { return false; }
|
|
bool take_missing_tile_notice(uint8_t* out)
|
|
{
|
|
if (out) *out = source_id;
|
|
const bool result = missing;
|
|
missing = false;
|
|
return result;
|
|
}
|
|
void set_map_render_options(uint8_t source, bool contour)
|
|
{
|
|
source_id = sanitize_map_source(source);
|
|
contours = contour;
|
|
}
|
|
void update_map_anchor(TileContext& c, double lat, double lon, int zoom, int pan_x, int pan_y, bool fix)
|
|
{
|
|
if (!c.anchor || !c.map_container) return;
|
|
auto& a = *c.anchor;
|
|
a.valid = fix;
|
|
if (!fix) return;
|
|
a.z = zoom;
|
|
a.n = std::ldexp(1.0, zoom);
|
|
int x, y;
|
|
latLngToTile(lat, lon, zoom, x, y);
|
|
a.gps_tile_x = x;
|
|
a.gps_tile_y = y;
|
|
a.gps_global_pixel_x = static_cast<int>(std::lround(world_x(lon, zoom)));
|
|
a.gps_global_pixel_y = static_cast<int>(std::lround(world_y(lat, zoom)));
|
|
a.gps_tile_pixel_x = x * 256;
|
|
a.gps_tile_pixel_y = y * 256;
|
|
a.gps_offset_x = a.gps_global_pixel_x - a.gps_tile_pixel_x;
|
|
a.gps_offset_y = a.gps_global_pixel_y - a.gps_tile_pixel_y;
|
|
a.gps_tile_screen_x = lv_obj_get_width(c.map_container) / 2 - a.gps_offset_x + pan_x;
|
|
a.gps_tile_screen_y = lv_obj_get_height(c.map_container) / 2 - a.gps_offset_y + pan_y;
|
|
}
|
|
bool gps_screen_pos(const TileContext& c, double lat, double lon, int& x, int& y)
|
|
{
|
|
if (!c.anchor || !c.anchor->valid) return false;
|
|
const auto& a = *c.anchor;
|
|
double dx = world_x(lon, a.z) - a.gps_global_pixel_x;
|
|
const double size = world_size(a.z);
|
|
if (dx > size / 2) dx -= size;
|
|
if (dx < -size / 2) dx += size;
|
|
x = std::lround(a.gps_tile_screen_x + a.gps_offset_x + dx);
|
|
y = std::lround(a.gps_tile_screen_y + a.gps_offset_y + world_y(lat, a.z) - a.gps_global_pixel_y);
|
|
return true;
|
|
}
|
|
bool tile_screen_pos_xyz(const TileContext& c, int x, int y, int z, int& sx, int& sy)
|
|
{
|
|
if (!c.anchor || !c.anchor->valid || c.anchor->z != z) return false;
|
|
const auto& a = *c.anchor;
|
|
int dx = x - a.gps_tile_x, n = 1 << z;
|
|
if (dx > n / 2) dx -= n;
|
|
if (dx < -n / 2) dx += n;
|
|
sx = a.gps_tile_screen_x + dx * 256;
|
|
sy = a.gps_tile_screen_y + (y - a.gps_tile_y) * 256;
|
|
return true;
|
|
}
|
|
void get_screen_center_lat_lng(const TileContext& c, double& lat, double& lon)
|
|
{
|
|
if (!c.anchor || !c.anchor->valid)
|
|
{
|
|
lat = lon = 0;
|
|
return;
|
|
}
|
|
const auto& a = *c.anchor;
|
|
world_geo(a.gps_global_pixel_x + lv_obj_get_width(c.map_container) / 2 - a.gps_tile_screen_x - a.gps_offset_x, a.gps_global_pixel_y + lv_obj_get_height(c.map_container) / 2 - a.gps_tile_screen_y - a.gps_offset_y, a.z, lat, lon);
|
|
}
|
|
bool tile_in_rect(int x, int y, int w, int h, int margin) { return x < w + margin && y < h + margin && x + 256 > -margin && y + 256 > -margin; }
|
|
void cleanup_tiles(TileContext& c)
|
|
{
|
|
if (c.tiles)
|
|
{
|
|
for (auto& t : *c.tiles)
|
|
{
|
|
if (t.img_obj) lv_obj_delete(t.img_obj);
|
|
if (t.contour_obj) lv_obj_delete(t.contour_obj);
|
|
}
|
|
c.tiles->clear();
|
|
}
|
|
if (c.has_map_data) *c.has_map_data = false;
|
|
if (c.has_visible_map_data) *c.has_visible_map_data = false;
|
|
}
|
|
void calculate_required_tiles(TileContext& c, double lat, double lon, int z, int px, int py, bool fix)
|
|
{
|
|
update_map_anchor(c, lat, lon, z, px, py, fix);
|
|
if (!c.tiles || !c.anchor || !c.anchor->valid) return;
|
|
bool any = false;
|
|
for (auto& t : *c.tiles)
|
|
{
|
|
t.visible = false;
|
|
if (t.img_obj) lv_obj_add_flag(t.img_obj, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
const int w = lv_obj_get_width(c.map_container), h = lv_obj_get_height(c.map_container);
|
|
double center_lat, center_lon;
|
|
get_screen_center_lat_lng(c, center_lat, center_lon);
|
|
for (auto xy : ui::map_tiles::tilesAround(center_lat, center_lon, z, w / 256 + 2, h / 256 + 2))
|
|
{
|
|
int sx, sy;
|
|
if (!tile_screen_pos_xyz(c, xy.x, xy.y, z, sx, sy) || !tile_in_rect(sx, sy, w, h, 0)) continue;
|
|
auto found = std::find_if(c.tiles->begin(), c.tiles->end(), [&](const auto& t)
|
|
{ return t.x == xy.x && t.y == xy.y && t.z == z && t.map_source == source_id; });
|
|
if (found == c.tiles->end())
|
|
{
|
|
MapTile t;
|
|
t.x = xy.x;
|
|
t.y = xy.y;
|
|
t.z = z;
|
|
t.map_source = source_id;
|
|
t.has_png_file = base_tile_available(z, t.x, t.y, source_id);
|
|
c.tiles->push_back(t);
|
|
found = c.tiles->end() - 1;
|
|
}
|
|
auto& tile = *found;
|
|
if (!tile.has_png_file)
|
|
{
|
|
missing = true;
|
|
continue;
|
|
}
|
|
if (!tile.img_obj)
|
|
{
|
|
tile.img_obj = lv_image_create(c.map_container);
|
|
char path[180];
|
|
build_base_tile_path(z, tile.x, tile.y, source_id, path, sizeof(path));
|
|
lv_image_set_src(tile.img_obj, path);
|
|
}
|
|
lv_obj_set_pos(tile.img_obj, sx, sy);
|
|
lv_obj_clear_flag(tile.img_obj, LV_OBJ_FLAG_HIDDEN);
|
|
tile.visible = true;
|
|
any = true;
|
|
}
|
|
if (c.has_map_data) *c.has_map_data = any;
|
|
if (c.has_visible_map_data) *c.has_visible_map_data = any;
|
|
}
|
|
void tile_loader_step(TileContext&) {}
|
|
void init_tile_context(TileContext& c, lv_obj_t* obj, MapAnchor* anchor, std::vector<MapTile>* tiles, ui::map_tiles::MapTileRenderQueue* queue, bool* has, bool* visible) { c = {obj, anchor, tiles, queue, has, visible}; }
|
|
void release_tile_context(TileContext& c)
|
|
{
|
|
cleanup_tiles(c);
|
|
c = {};
|
|
}
|