Files
fn_registry/dev/issues/0035-cpp-map-tiles.md
T
egutierrez 461bb77298 docs(issues): añadir 0025-0036 — features C++ para registry y primitives_gallery
12 issues nuevos para implementacion paralela: text_editor, file_watcher,
gl_texture_load, gl_compute+pingpong+DAG Compute, ImPlot3D, mesh_viewer,
audio reactivo, animation curves, sql_workbench, http+ws inspector,
scientific viz (5 charts), map_tiles, image_canvas + webcam_texture.

Cada issue añade funciones al registry y un demo propio en
primitives_gallery/demos_<feature>.cpp para minimizar conflictos en paralelo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:48:18 +02:00

4.5 KiB

0035 — C++ map_tiles (slippy map OSM)

APP Metadata

Campo Valor
ID 0035
Estado pendiente
Prioridad baja
Tipo feature — C++ viz (cpp/functions/viz)

Dependencias

gl_texture_load_cpp_gfx (issue 0026), gl_loader_cpp_gfx. Vendor: cpp-httplib (si ya esta vendoreado por 0033) o reusar.

Desbloquea: apps GIS minimas, dashboards con localizacion (entities con lat/lon), debugging de scrapers geograficos.


Objetivo

Componente ImGui que renderiza un slippy map estilo Leaflet sobre OpenStreetMap tiles, con pan/zoom y soporte para markers + polylines.

Contexto

Hay datos geograficos en varios proyectos (registry de proveedores, viajes, infrastructura). No hay forma de visualizarlos en C++; se exporta a una notebook con folium o se monta un frontend React.

Arquitectura

cpp/functions/viz/
├── map_tiles.h                  # NEW
├── map_tiles.cpp                # NEW
└── map_tiles.md                 # NEW (impure)
cpp/apps/primitives_gallery/
├── demos_map.cpp                # NEW
├── demos.h                      # MOD
├── main.cpp                     # MOD
└── CMakeLists.txt               # MOD

API propuesta

namespace fn {

struct MapMarker  { double lat, lon; ImU32 color; const char* label; };
struct MapPolyline { std::vector<ImVec2> latlon; ImU32 color; float thickness = 2.f; };  // ImVec2 = (lat, lon)
struct MapState {
    double lat = 40.4168;       // Madrid default
    double lon = -3.7038;
    int    zoom = 6;            // 0..18
    std::string tile_url = "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
    std::string user_agent = "fn-registry-map/0.1 (egutierrez@aurgi.com)";
    bool   show_attribution = true;  // OSM atribucion obligatoria
};

void map_tiles(const char* id, MapState&,
               const MapMarker* markers, int n_markers,
               const MapPolyline* polylines, int n_polylines,
               ImVec2 size = {-1, -1});
}

Tareas

Fase 1 — Tile cache

  • 1.1 Cache en disco bajo ~/.cache/fn-registry/tiles/{z}/{x}/{y}.png. Crear directorio si no existe.
  • 1.2 Cache en RAM (LRU) de GlTexture ya subidas, max 256 entradas.
  • 1.3 Funcion tile_get_or_fetch(z, x, y): si en RAM → return; si en disco → load (gl_texture_load); si no → spawn thread que descarga via cpp-httplib y guarda en disco. Mientras tanto, devolver placeholder.

Fase 2 — Proyeccion + interaction

  • 2.1 Funciones puras lonlat_to_xy(lat, lon, zoom) -> (px, py) y xy_to_lonlat.
  • 2.2 map_tiles_handle_input: drag pan, wheel zoom (clamp 0-18), mantener punto bajo cursor durante zoom.

Fase 3 — Render

  • 3.1 Calcular tiles visibles dado el viewport y zoom.
  • 3.2 Para cada tile visible: ImGui::Image(texture, screen_rect) o AddImage en el DrawList.
  • 3.3 Markers: AddCircleFilled + texto.
  • 3.4 Polylines: convertir lat/lon a screen y AddPolyline.
  • 3.5 Atribucion en esquina inferior derecha: "© OpenStreetMap contributors".

Fase 4 — User-Agent + ToS

  • 4.1 Enviar User-Agent custom (OSM lo exige). Documentar en .md que el usuario debe poner su contacto.
  • 4.2 Cap a 2 requests/segundo simultaneos para no abusar del tile server.
  • 5.1 demos_map.cpp con demo_map_tiles(): mapa centrado en Espana, 5 markers en ciudades, polyline conectandolas.
  • 5.2 Registrar.

Fase 6 — Tests + docs

  • 6.1 Tests puros de proyeccion (Madrid → conocidos pixels a zoom 10).
  • 6.2 ./fn index + ./fn show map_tiles_cpp_viz.

Ejemplo de uso

fn::MapState m;
fn::MapMarker markers[] = {
    {40.4168, -3.7038, IM_COL32(255,80,80,255), "Madrid"},
    {41.3851,  2.1734, IM_COL32(80,150,255,255), "Barcelona"},
};
fn::map_tiles("##m", m, markers, 2, nullptr, 0);

Decisiones de diseño

  • OSM tile server por defecto: gratis, sin API key. Documentar limite y alternativa (carto, stamen) cambiando tile_url.
  • Cache en ~/.cache/fn-registry/tiles/: respeta XDG; persistente entre runs.
  • Sin GeoJSON parsing en MVP: solo markers/polylines via API. GeoJSON en issue futuro.

Riesgos

  • Bloqueo de IP por OSM: documentar terminos de uso (max 1 req/s recomendado, User-Agent unico).
  • Tiles a alta latitud: documentar que la proyeccion Web Mercator distorsiona >85°.
  • Threading de descargas: cuidado con marshalling de texturas GL (deben crearse en hilo con contexto). Patron: descargar PNG bytes en thread, crear GL texture en main thread.