SXXXXXXX_GeoElevation/doc/map_manager.md
2025-12-02 09:50:29 +01:00

8.2 KiB

Ecco il piano operativo completo per il refactoring e la creazione del modulo python-map-manager. Questo documento è strutturato per essere inserito direttamente nella documentazione tecnica del progetto.


Piano Operativo: Refactoring e Creazione Modulo python-map-manager

1. Obiettivo del Refactoring

L'obiettivo primario è disaccoppiare la logica di gestione, recupero e visualizzazione delle mappe geografiche (attualmente integrata nell'applicazione geoelevation) per creare un componente software autonomo, riutilizzabile e manutenibile separatamente.

Questo nuovo componente sarà gestito come Git Submodule e denominato python-map-manager.

Obiettivi Specifici

  1. Indipendenza: Il modulo non deve avere dipendenze dalla logica di business dell'applicazione ospite (es. non deve conoscere ElevationManager).
  2. Modularità: Separazione netta tra logica di elaborazione (Engine) e logica di visualizzazione (Visualizer).
  3. Testabilità: Inclusione di un tool di debug integrato (debug_tool.py) per lo sviluppo e il test isolato delle funzionalità.
  4. Interfaccia Chiara: Esposizione di API semplici per richiedere immagini di mappe basate su aree, punti o raggi.

2. Architettura del Nuovo Modulo

Il modulo python-map-manager esporrà due componenti principali:

A. MapEngine (Logica Backend)

È il cervello del modulo. Non ha interfaccia grafica.

  • Responsabilità:
    • Gestione dei provider di mappe (es. OpenStreetMap).
    • Gestione della cache su disco (download, salvataggio, recupero).
    • Calcoli matematici (conversioni coordinate Geo <-> Pixel, calcolo Bounding Box).
    • Stitching (unione) delle tile per formare un'unica immagine PIL.
  • Funzionalità Chiave:
    • get_image_for_area(bbox, max_size): Restituisce un'immagine ottimizzata per coprire un'area.
    • get_image_for_point(lat, lon, zoom, size): Restituisce un'immagine centrata su un punto.

B. MapVisualizer (Interfaccia Frontend - Opzionale)

È il componente di visualizzazione interattiva (basato su OpenCV).

  • Responsabilità:
    • Apertura e gestione della finestra grafica.
    • Gestione dell'input utente (Mouse, Zoom, Pan).
    • Rendering dell'immagine fornita dall'Engine.
  • Disaccoppiamento:
    • Invece di chiamare funzioni esterne, il Visualizer emette Eventi (tramite callback) quando l'utente interagisce (es. on_map_click, on_area_selected). L'applicazione ospite si sottoscrive a questi eventi.

3. Struttura del Repository python-map-manager

python-map-manager/
├── map_manager/                # Package Python principale
│   ├── __init__.py             # Espone MapEngine e MapVisualizer
│   ├── engine.py               # Classe MapEngine (Facade logica)
│   ├── visualizer.py           # Classe MapVisualizer (Gestione Window/OpenCV)
│   ├── tile_manager.py         # Gestione download e cache (ex map_manager.py)
│   ├── services.py             # Definizioni Provider Mappe (ex map_services.py)
│   ├── utils.py                # Calcoli geografici puri (ex map_utils.py)
│   └── drawing.py              # Funzioni di disegno su PIL (ex map_drawing.py)
├── debug_tool.py               # Tool CLI/GUI per testare il modulo isolatamente
├── requirements.txt            # Dipendenze (requests, Pillow, opencv-python, mercantile, pyproj)
└── README.md                   # Documentazione API

4. Fasi di Implementazione

Fase 1: Setup dell'Ambiente e Migrazione File "Puri"

In questa fase si crea la struttura base e si migrano le librerie di utilità che non richiedono refactoring logico.

  1. Creare la cartella python-map-manager e inizializzare git.
  2. Creare la struttura cartelle map_manager/.
  3. Migrazione Diretta:
    • Copiare geoelevation/map_viewer/map_services.py -> map_manager/services.py.
    • Copiare geoelevation/map_viewer/map_utils.py -> map_manager/utils.py.
    • Copiare geoelevation/map_viewer/map_drawing.py -> map_manager/drawing.py.
    • Copiare geoelevation/map_viewer/map_manager.py -> map_manager/tile_manager.py (Rinominato per chiarezza).
  4. Normalizzazione Import: Aggiornare gli import interni ai file copiati per puntare ai nuovi percorsi relativi (es. from .services import ... invece di from .map_services import ...).

Fase 2: Implementazione di MapEngine (engine.py)

In questa fase si astrae la logica di calcolo e recupero immagini.

  1. Creare map_manager/engine.py.
  2. Definire la classe MapEngine.
  3. Implementare il metodo __init__ per configurare il MapTileManager e la cache.
  4. Implementare get_image_for_area:
    • Deve accettare coordinate (min_lat, min_lon, max_lat, max_lon).
    • Deve usare utils.py per calcolare lo zoom ottimale in base alle dimensioni pixel richieste.
    • Deve chiamare tile_manager.stitch_map_image.
  5. Implementare get_image_for_point:
    • Accetta centro e livello di zoom.
    • Calcola il Bounding Box necessario usando utils.py.
    • Richiede lo stitching.

Fase 3: Implementazione di MapVisualizer (visualizer.py)

In questa fase si crea il gestore della finestra, rimuovendo ogni logica di business specifica di geoelevation.

  1. Creare map_manager/visualizer.py.
  2. Definire la classe MapVisualizer che accetta un'istanza di MapEngine.
  3. Estrarre la logica OpenCV da geo_map_viewer.py e map_display.py.
  4. Implementare il loop di gestione eventi mouse (cv2.setMouseCallback).
  5. Refactoring Eventi:
    • Definire una proprietà callback_on_click (funzione che accetta lat, lon).
    • Quando avviene un click, usare engine o utils per convertire Pixel -> Lat/Lon.
    • Invocare self.callback_on_click(lat, lon) invece di chiamare elevation_manager.

Fase 4: Creazione del debug_tool.py

Uno strumento essenziale per garantire che il modulo funzioni "out of the box".

  1. Creare debug_tool.py nella root del repository.
  2. Lo script deve:
    • Istanziare MapEngine (con una cache temporanea o di debug).
    • Istanziare MapVisualizer.
    • Definire una funzione dummy: def on_click(lat, lon): print(f"Clicked: {lat}, {lon}").
    • Collegare la funzione al visualizzatore.
    • Avviare la mappa su coordinate di default (es. Roma).
  3. Questo tool servirà per verificare lo zoom, il pan e la correttezza del download delle tile.

Fase 5: Integrazione nell'Applicazione Principale

Una volta che il submodule è stabile e pushato sul repository remoto.

  1. In geoelevation, rimuovere la cartella map_viewer esistente.
  2. Aggiungere il submodule:
    git submodule add -b master <URL_REPO> external/python-map-manager
    
  3. Configurare i path in geoelevation/__init__.py (o file di setup path dedicato) per includere il submodule.
  4. Modificare geoelevation/process_targets.py (o dove risiede il processo mappa):
    • Importare MapEngine e MapVisualizer dal submodule.
    • Nel processo dedicato alla mappa, definire la funzione di callback reale che interroga ElevationManager.
    • Passare questa callback al MapVisualizer.

5. Specifiche Tecniche e Standard

  • PEP8: Tutto il codice deve seguire rigorosamente lo standard PEP8.
  • Type Hinting: Ogni funzione deve avere le annotazioni di tipo (-> Optional[Image.Image], ecc.).
  • Docstrings: Ogni classe e metodo pubblico deve avere docstring in Inglese.
  • Dipendenze:
    • Non usare try-except ImportError per nascondere dipendenze mancanti all'interno del modulo. Se MapVisualizer richiede OpenCV, l'import deve fallire esplicitamente se manca, o essere gestito a livello di __init__.py per esporre le funzionalità disponibili.
    • Il file requirements.txt deve elencare le versioni minime testate.

6. Risultato Atteso

Al termine di questo processo, avremo:

  1. Un repository python-map-manager autonomo.
  2. La possibilità di sviluppare e migliorare la gestione mappe lanciando solo python debug_tool.py.
  3. L'applicazione geoelevation più leggera, che delega tutta la complessità cartografica al modulo esterno, mantenendo solo la logica di "cosa fare quando l'utente clicca un punto" (ovvero chiedere l'elevazione).